feat: Community Translation v1 - #3765
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughThis PR adds public project publishing/listing, community permission flooring and member masking, new suggestion-management scopes and language fields, and updated suggestion preview/moderation flows across backend, webapp, and tests. ChangesPublic projects and community permissions
Estimated code review effort: 5 (Critical) | ~120 minutes Possibly related issues
Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 inconclusive)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
d9ca48a to
ec88b34
Compare
There was a problem hiding this comment.
Actionable comments posted: 18
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
webapp/src/views/projects/translations/context/services/useEditService.tsx (1)
191-206: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winDedupe by
idwhen merging the new suggestion intovalue.suggestions.Without a dedup check, a subsequent update to
value.suggestions(e.g. from a refetch or another local update path) that also contains this suggestion could leave the array with a duplicate entry for the sameid, breaking thekey={s.id}React key contract inSuggestionsFirst/TranslationSuggestion.🐛 Suggested fix
- suggestions: [result, ...(value.suggestions ?? [])].slice( - 0, - MAX_DISPLAYED_SUGGESTIONS - ), + suggestions: [ + result, + ...(value.suggestions ?? []).filter((s) => s.id !== result.id), + ].slice(0, MAX_DISPLAYED_SUGGESTIONS),🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@webapp/src/views/projects/translations/context/services/useEditService.tsx` around lines 191 - 206, The suggestion merge in useEditService’s updateTranslation data callback should dedupe by id before prepending the new result, since value.suggestions may already contain the same suggestion from another update path. Update the logic around result, value.suggestions, and MAX_DISPLAYED_SUGGESTIONS so the merged array keeps only one entry per s.id while preserving the existing count updates.backend/data/src/main/kotlin/io/tolgee/repository/PermissionRepository.kt (1)
41-52: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick winRestore
sul.id is not nullinfindAllByPermittedLanguage()
PermissionService.removeLanguageFromPermissions()uses this query, butLanguageDeletedPermissionUpdaternever removessuggestLanguages. Withoutsul.id is not null, permissions that only reference the deleted language throughsuggestLanguagesare skipped and keep a stale relation.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@backend/data/src/main/kotlin/io/tolgee/repository/PermissionRepository.kt` around lines 41 - 52, `findAllByPermittedLanguage()` is missing the `suggestLanguages` check, so permissions linked only through that relation are not returned. Update the query in `PermissionRepository.findAllByPermittedLanguage` to include `sul.id is not null` alongside the existing `tl`, `vl`, `scl`, and `sml` conditions so `PermissionService.removeLanguageFromPermissions()` can remove stale `suggestLanguages` references.webapp/src/views/projects/translations/Suggestions/TranslationSuggestion.tsx (1)
198-212: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winTooltip can render blank when name is unset and username is masked to
"".
suggestion.author.name ?? suggestion.author.usernameonly falls back on nullishname; it doesn't handleusernamebeing masked to an empty string (confirmed by the updated assertions inSuggestionControllerTest.ktexpectingauthor.username==""). If an author has nonameset, the tooltip (and theAvatarImgavatar, which spreads the sameauthor) would show blank.🐛 Proposed fix
params={{ - user: suggestion.author.name ?? suggestion.author.username, + user: suggestion.author.name || suggestion.author.username || t('global_unknown_user'), b: <b />, }}🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@webapp/src/views/projects/translations/Suggestions/TranslationSuggestion.tsx` around lines 198 - 212, The tooltip and avatar author lookup in TranslationSuggestion should not rely on suggestion.author.name ?? suggestion.author.username alone, since username may be an empty masked string. Update the author label logic used by the Tooltip title and the AvatarImg owner in TranslationSuggestion to fall back to a non-blank display value when name is missing and username is empty, using the suggestion.author object as the source of truth.
🧹 Nitpick comments (10)
backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/PublicProjectsE2eData.kt (1)
9-23: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick winSilent truncation when
count > 6.
take(count)on a 6-element list silently caps output at 6 regardless of a largercountargument, which could mislead future callers into thinking more projects were seeded.🛡️ Guard against an out-of-range count
class PublicProjectsE2eData( count: Int = 6, ) : BaseTestData("publicProjectsUser", "Private project") { init { + require(count in 1..6) { "count must be between 1 and 6" } root.apply {🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/PublicProjectsE2eData.kt` around lines 9 - 23, `PublicProjectsE2eData` silently caps seeded projects at 6 because the `listOf(...).take(count)` source is fixed-length; update the `init` block to validate or constrain `count` explicitly so callers can’t request more than the available suffixes without being told. If `count` should be limited, guard it up front in `PublicProjectsE2eData` and fail fast or clamp with an intentional message; if more than 6 projects should be supported, replace the hardcoded suffix list with a generator that can produce enough unique names before calling `addProject`.webapp/src/views/projects/translations/context/services/useEditService.tsx (1)
20-20: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winUse
tg.viewsalias instead of a cross-directory relative import.As per coding guidelines, "Use Tolgee custom TypeScript path aliases (tg.component, tg.service, tg.hooks, tg.views, tg.globalContext) instead of relative imports".
♻️ Suggested fix
-import { MAX_DISPLAYED_SUGGESTIONS } from '../../Suggestions/SuggestionsFirst'; +import { MAX_DISPLAYED_SUGGESTIONS } from 'tg.views/projects/translations/Suggestions/SuggestionsFirst';🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@webapp/src/views/projects/translations/context/services/useEditService.tsx` at line 20, The import in useEditService should use the tg.views alias instead of a cross-directory relative path. Update the MAX_DISPLAYED_SUGGESTIONS import to point through the views alias so it follows the project’s Tolgee path-alias convention and avoids relative imports across directories.Source: Coding guidelines
backend/data/src/main/kotlin/io/tolgee/model/Project.kt (1)
175-175: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueConsider a less keyword-adjacent property name.
var public: Booleanshadows the readability of thepublicvisibility modifier elsewhere in the class.isPublicwould be more idiomatic Kotlin and self-documenting, while@Column(name = "is_public")keeps the DB mapping intact.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@backend/data/src/main/kotlin/io/tolgee/model/Project.kt` at line 175, Rename the Project property currently named public to a more idiomatic boolean name like isPublic so it does not read like the Kotlin visibility keyword and is clearer at call sites. Update the Project class property definition and any usages/accessors in the diff to match the new name, while keeping the existing database mapping intact via the current column annotation.e2e/cypress/e2e/projects/communityProjectsNavigation.cy.ts (2)
195-209: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winText-content selectors used instead of
data-cy.
cy.contains('Community Alpha'),cy.contains('Community Zeta'), andcy.contains('Private project')select/assert purely on rendered text, which breaks on copy/i18n changes.As per coding guidelines, "STRICTLY use
data-cyattributes for E2E selectors, never rely on text content; use typed helpersgcy()orcy.gcy()."🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@e2e/cypress/e2e/projects/communityProjectsNavigation.cy.ts` around lines 195 - 209, The community projects navigation spec is using text-based assertions instead of stable E2E selectors. Update the checks in communityProjectsNavigation.cy.ts to use data-cy via gcy()/cy.gcy() for the project items and badge visibility, and avoid cy.contains for “Community Alpha”, “Community Zeta”, and “Private project”. Keep the existing test intent in the affected it blocks, but reference the same selector helpers already used in this file such as gcy('dashboard-projects-list-item'), gcy('project-list-public-badge'), and gcy('global-list-search').Source: Coding guidelines
78-106: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winText-content chained on
gcyselectors.
gcy('organization-switch').contains('Microsoft')andgcy('global-base-view-title').contains('Projects')still rely on text content for the final assertion/target rather than a nesteddata-cyelement.As per coding guidelines, "STRICTLY use
data-cyattributes for E2E selectors, never rely on text content."🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@e2e/cypress/e2e/projects/communityProjectsNavigation.cy.ts` around lines 78 - 106, The Cypress assertions in communityProjectsNavigation.cy.ts are still using text-based chaining on gcy selectors, which violates the data-cy-only selector rule. Update the affected checks in the community switcher and Projects title tests to target nested data-cy elements instead of contains text, using the existing gcy and findDcy patterns around organization-switch and global-base-view-title so the assertions rely only on data-cy attributes.Source: Coding guidelines
e2e/cypress/e2e/projects/suggestions/suggestions.reviewer.cy.ts (1)
268-291: 📐 Maintainability & Code Quality | 🔵 Trivial | 🏗️ Heavy liftRow lookup relies on text content instead of a distinguishing
data-cyattribute.
acceptOnlyandopenRowMenulocate the target suggestion via.contains(text)against translated suggestion copy. This pattern is reused across nearly every test in this file, so any change in suggestion phrasing/i18n breaks the whole suite.As per coding guidelines, "STRICTLY use
data-cyattributes for E2E selectors, never rely on text content; use typed helpersgcy()orcy.gcy()." Consider exposing a stable per-row identifier (e.g.data-cy-valuekeyed to suggestion id/index) so rows can be targeted without text matching.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@e2e/cypress/e2e/projects/suggestions/suggestions.reviewer.cy.ts` around lines 268 - 291, The row-targeting helpers acceptOnly and openRowMenu rely on translated text via .contains(text), which makes the tests fragile. Update these helpers and the related callers in suggestions.reviewer.cy.ts to target each translation-suggestion row using a stable data-cy-based identifier instead of visible copy, ideally by adding a per-row value such as a suggestion id/index and selecting it through cy.gcy() or gcyAdvanced(). Keep the action clicks the same, but remove text matching so the suite no longer depends on suggestion phrasing or i18n.Source: Coding guidelines
webapp/src/component/SwitchPopover/SwitchPopover.tsx (1)
88-93: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winMake
footerAction.dataCyrequired to guarantee E2E testability.
dataCyis optional, so a future caller could add afooterActionwithout adata-cyselector, making it unreachable from Cypress tests. As per coding guidelines, "STRICTLY usedata-cyattributes for E2E selectors, never rely on text content."♻️ Proposed fix
footerAction?: { content: React.ReactNode; onClick: () => void; - dataCy?: string; + dataCy: string; };Also applies to: 236-247
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@webapp/src/component/SwitchPopover/SwitchPopover.tsx` around lines 88 - 93, Make footerAction.dataCy required in SwitchPopover’s footerAction type so every action has a Cypress selector. Update the footerAction interface and any related props/usage in SwitchPopover and the affected call sites so they always pass a dataCy value. Use the footerAction symbol and any rendering logic that wires the selector to the footer action button to keep E2E testability guaranteed.Source: Coding guidelines
webapp/src/views/projects/translations/Suggestions/TranslationSuggestion.tsx (1)
131-172: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winAdd
defaultValuefor the new translation keys.
translation_suggestion_accept_onlyandtranslation_suggestion_accept_and_decline_othersappear to be new keys introduced by this PR's suggestion-split feature. As per coding guidelines, always providedefaultValuefor new keys so the UI shows meaningful text before they're uploaded to Tolgee.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@webapp/src/views/projects/translations/Suggestions/TranslationSuggestion.tsx` around lines 131 - 172, The new translation keys used in TranslationSuggestion are missing required default text. Update the calls in TranslationSuggestion so the t() lookups for translation_suggestion_accept_only and translation_suggestion_accept_and_decline_others include defaultValue strings, alongside the existing translation_suggestion_accept_tooltip and translation_suggestion_reverse_tooltip usages, so the labels remain meaningful before Tolgee sync.Source: Coding guidelines
backend/app/src/main/kotlin/io/tolgee/configuration/WebSecurityConfig.kt (1)
138-146: 🔒 Security & Privacy | 🔵 TrivialConsider enforcing this invariant with a test, not just a comment.
The comment correctly flags a real risk: any future
/v2/public/**controller using{projectId}/{organizationId}path vars with@RequiresProjectPermissionswould silently bypass authorization since these interceptors aren't registered for public endpoints. Comments can't catch regressions; consider adding an architecture test (e.g. ArchUnit rule scanning for@RequiresProjectPermissionson handlers mapped under/v2/public/**) to fail the build if this invariant is ever violated.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@backend/app/src/main/kotlin/io/tolgee/configuration/WebSecurityConfig.kt` around lines 138 - 146, Add a regression test that enforces the public-route authorization invariant in WebSecurityConfig by scanning controllers/handlers under /v2/public/** for any use of `@RequiresProjectPermissions` together with {projectId}/{organizationId} path vars and failing the build if found. Use a test such as an ArchUnit rule or equivalent around the relevant annotations and mappings so future public endpoints cannot silently bypass the organizationAuthorizationInterceptor/projectAuthorizationInterceptor restriction.ee/backend/app/src/main/kotlin/io/tolgee/ee/api/v2/controllers/SuggestionController.kt (1)
142-150: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winPreserve the original cause when rewrapping
PermissionException.
PermissionExceptionhas no cause-taking constructor, so this catch block drops the root exception. Add a cause-aware overload (viaExceptionWithMessage) or avoid rewrapping here.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@ee/backend/app/src/main/kotlin/io/tolgee/ee/api/v2/controllers/SuggestionController.kt` around lines 142 - 150, The PermissionException handling in SuggestionController.checkLanguageSuggestionsManagePermission currently rethrows a new exception and loses the original cause; update this catch block to preserve the underlying exception by using a cause-aware path (for example via ExceptionWithMessage) or by avoiding the rewrap entirely. Keep the existing special handling for LanguageNotPermittedException, and adjust the PermissionException branch so the original throwable is carried forward while still mapping to Message.USER_CAN_ONLY_DELETE_HIS_SUGGESTIONS.Source: Linters/SAST tools
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/CommunityPermissionTest.kt`:
- Around line 20-25: `CommunityPermissionTest.setup()` creates and saves
`ProjectPublishingTestData` but never cleans it up, so add an `@AfterEach`
cleanup that removes the saved `testData` using the same test data lifecycle
pattern used elsewhere. Keep `testData` as the instance to clean, and ensure the
cleanup runs after every test so state does not leak between runs.
In
`@backend/app/src/test/kotlin/io/tolgee/service/ProjectPublishingCachingTest.kt`:
- Around line 20-28: `ProjectPublishingCachingTest` sets up persistent
`BaseTestData` in `setup()` but never cleans it up, leaving test data behind
between runs. Add an `@AfterEach` cleanup method in
`ProjectPublishingCachingTest` that removes the saved `testData` using the
existing test-data cleanup pattern, and keep the `BaseTestData` lifecycle
symmetrical with `testDataService.saveTestData(testData.root)` so the test setup
is created and torn down within the same class.
In `@backend/data/src/main/kotlin/io/tolgee/model/Permission.kt`:
- Around line 107-113: The organization base-permission check in
Permission.prePersist is missing the suggest language sets, so update that
invariant to include both suggestLanguages and suggestManageLanguages alongside
viewLanguages, translateLanguages, and stateChangeLanguages. Make sure the guard
rejects any non-empty language restriction on an organization base Permission,
and keep the existing logic centralized in Permission so the new
suggestManageLanguages field is covered too.
In `@e2e/cypress/e2e/projects/communityProjectsNavigation.cy.ts`:
- Line 26: The test data setup in the communityProjectsNavigation Cypress spec
is using the outdated organizationTestData.generate() pattern; replace it with
organizationTestData.generateStandard() in the affected test flow, including the
other matching occurrence noted in the same spec, so the E2E test follows the
standard data generation approach.
In `@e2e/cypress/e2e/projects/publicProjects.cy.ts`:
- Line 22: Replace the outdated test data generation calls in
publicProjects.cy.ts by using publicProjectsData.generateStandard() instead of
publicProjectsData.generate() wherever the current generate() pattern appears.
Update each affected test setup to call the standard generator consistently so
the publicProjectsData fixture follows the E2E coding guideline.
- Around line 37-39: Replace the text-based Cypress assertions in the public
projects test with `data-cy`-driven selectors using `gcy()` or `cy.gcy()`. In
the `publicProjects.cy.ts` spec, update the checks around the `Community Alpha`,
`Community Zeta`, and `Private project` assertions so they target the relevant
elements by their stable `data-cy` attributes instead of `cy.contains(...)`,
keeping the same visibility/existence expectations.
In `@e2e/cypress/e2e/projects/suggestions/suggestions.translator.cy.ts`:
- Around line 71-89: The suggestion deletion test is using translated text via
.contains('Navržený překlad 0-1') instead of stable E2E hooks. Update the
selector chain in the translator spec to scope the target card using
data-cy-based helpers only, ideally through cy.gcy()/gcyAdvanced on the
translation-suggestion element and its child action menu. Keep the same delete
flow, but remove all text-content matching so the test relies on stable
identifiers rather than localized copy.
In `@e2e/cypress/e2e/projects/suggestions/suggestions.unprotected.cy.ts`:
- Around line 48-53: The suggestion selection in the Cypress spec is still using
translated text and a raw closest selector, which bypasses the data-cy-only E2E
standard. Update the test to target the suggestion card via a stable data-cy
identifier using the existing gcy/cy.gcy helpers, and avoid .contains() on
“Navržený překlad 0-1” and the manual
closest('[data-cy="translation-suggestion"]'). If needed, add a unique data-cy
on the suggestion item in the UI and use that stable selector in the test around
gcyAdvanced and the translation-suggestion card.
In
`@ee/backend/tests/src/test/kotlin/io/tolgee/ee/api/v2/controllers/SuggestionControllerTest.kt`:
- Around line 32-53: The `@AfterEach` cleanup in resetClock only clears the forced
date, so persisted SuggestionsTestData from initTestData can leak into later
tests. Update resetClock in SuggestionControllerTest to also invoke
testDataService.cleanTestData(testData.root) after clearForcedDate, using the
existing testDataService and testData symbols so all saved projects and
suggestions are removed after each test.
In `@webapp/src/component/organizationSwitch/CommunityTranslationItem.tsx`:
- Line 19: The CommunityTranslationItem component is calling
t('community_translation_switch_item') without a defaultValue, which can leave
the UI blank before the translation exists in Tolgee. Update the t() usage in
CommunityTranslationItem to include a meaningful defaultValue so the label
always renders readable text, following the existing i18n pattern used elsewhere
in the app.
In `@webapp/src/component/PermissionsSettings/LanguagePermissionsSummary.tsx`:
- Around line 20-21: The LanguagePermissionsSummary component is omitting
suggest-manage-only languages because languagesUnion and the derived
hintNeeded/tooltip logic in the summary do not include suggestManageLanguageIds
even though it is already present in categories. Update the union construction
in LanguagePermissionsSummary so suggestManageLanguageIds participates alongside
viewLanguageIds, translateLanguageIds, and stateChangeLanguageIds, and ensure
the chip/tooltip rendering paths still use that same union-derived set.
In `@webapp/src/views/projects/CommunityProjectsView.tsx`:
- Line 56: The new translation keys in CommunityProjectsView are missing
defaultValue, so the UI can render raw key names before Tolgee syncs. Update the
t() usage for community_projects_window_title and the T component/string for
public_projects_empty to include meaningful defaultValue text, following the
project guideline that all new translation keys must provide a fallback.
In `@webapp/src/views/projects/DashboardProjectListItem.tsx`:
- Around line 201-207: The new translation key used in DashboardProjectListItem
via t('project_list_public_badge') is missing a defaultValue, so the badge can
render blank before Tolgee updates. Update the translation call in
StyledPublicChip to include a meaningful defaultValue for
project_list_public_badge, following the same pattern used elsewhere in the
project for new T/t() keys.
- Around line 178-186: The onClick handler in DashboardProjectListItem currently
sends unauthenticated users directly to LINKS.LOGIN.build() without preserving
the project they clicked, so the post-login redirect cannot return them to that
project. Update the isPublicVariant && !allowPrivate branch to save the intended
project destination as the afterLoginLink before navigating to login, using the
same project URL that LINKS.PROJECT_DASHBOARD.build creates for p.id, while
keeping the existing history.push flow intact.
In `@webapp/src/views/projects/project/ProjectSettingsAdvanced.tsx`:
- Around line 62-77: The new public-project translation keys are used in
ProjectSettingsAdvanced without fallback text, so add defaultValue to each T
usage involved in the public/private section and the make-public/make-private
dialog content. Update the relevant T components in ProjectSettingsAdvanced so
the title and message (and the public section labels/hint in the same component)
all provide meaningful default text for project_settings_public_section_title,
project_settings_public_label, project_settings_public_hint,
project_settings_make_public_dialog_title,
project_settings_make_private_dialog_title,
project_settings_make_public_confirmation, and
project_settings_make_private_confirmation.
In `@webapp/src/views/projects/ProjectListView.tsx`:
- Around line 60-68: The ProjectListView search handler only updates search text
and does not reset pagination, which can leave the view on an invalid page after
filtering. Update the search flow in ProjectListView so the handler passed to
BaseView.onSearch also resets page to 0 when a new search is entered, matching
the behavior used in CommunityProjectsView.tsx. Keep the change localized to the
search state update path and use the existing setSearch and setPage state
setters.
In `@webapp/src/views/projects/translations/Suggestions/SuggestionsFirst.tsx`:
- Line 74: The new translation lookup in SuggestionsFirst using
t('translation_tools_suggestions_show_all_label') is missing a defaultValue, so
add a meaningful fallback string to this call. Update the t() usage in
SuggestionsFirst to include defaultValue so the UI shows readable text before
the translation is available in Tolgee.
In `@webapp/src/views/projects/translations/Suggestions/SuggestionsList.tsx`:
- Around line 140-150: The mapping in SuggestionsList uses inconsistent optional
chaining for firstPage: the suggestions slice is guarded, but
activeSuggestionCount still reads firstPage.page?.totalElements directly and can
throw if firstPage is undefined. Update the onSuccess transformation in
SuggestionsList to safely handle a missing firstPage by using the same optional
chaining pattern for activeSuggestionCount, falling back to 0 when
suggestions.pages is empty.
---
Outside diff comments:
In `@backend/data/src/main/kotlin/io/tolgee/repository/PermissionRepository.kt`:
- Around line 41-52: `findAllByPermittedLanguage()` is missing the
`suggestLanguages` check, so permissions linked only through that relation are
not returned. Update the query in
`PermissionRepository.findAllByPermittedLanguage` to include `sul.id is not
null` alongside the existing `tl`, `vl`, `scl`, and `sml` conditions so
`PermissionService.removeLanguageFromPermissions()` can remove stale
`suggestLanguages` references.
In `@webapp/src/views/projects/translations/context/services/useEditService.tsx`:
- Around line 191-206: The suggestion merge in useEditService’s
updateTranslation data callback should dedupe by id before prepending the new
result, since value.suggestions may already contain the same suggestion from
another update path. Update the logic around result, value.suggestions, and
MAX_DISPLAYED_SUGGESTIONS so the merged array keeps only one entry per s.id
while preserving the existing count updates.
In
`@webapp/src/views/projects/translations/Suggestions/TranslationSuggestion.tsx`:
- Around line 198-212: The tooltip and avatar author lookup in
TranslationSuggestion should not rely on suggestion.author.name ??
suggestion.author.username alone, since username may be an empty masked string.
Update the author label logic used by the Tooltip title and the AvatarImg owner
in TranslationSuggestion to fall back to a non-blank display value when name is
missing and username is empty, using the suggestion.author object as the source
of truth.
---
Nitpick comments:
In `@backend/app/src/main/kotlin/io/tolgee/configuration/WebSecurityConfig.kt`:
- Around line 138-146: Add a regression test that enforces the public-route
authorization invariant in WebSecurityConfig by scanning controllers/handlers
under /v2/public/** for any use of `@RequiresProjectPermissions` together with
{projectId}/{organizationId} path vars and failing the build if found. Use a
test such as an ArchUnit rule or equivalent around the relevant annotations and
mappings so future public endpoints cannot silently bypass the
organizationAuthorizationInterceptor/projectAuthorizationInterceptor
restriction.
In
`@backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/PublicProjectsE2eData.kt`:
- Around line 9-23: `PublicProjectsE2eData` silently caps seeded projects at 6
because the `listOf(...).take(count)` source is fixed-length; update the `init`
block to validate or constrain `count` explicitly so callers can’t request more
than the available suffixes without being told. If `count` should be limited,
guard it up front in `PublicProjectsE2eData` and fail fast or clamp with an
intentional message; if more than 6 projects should be supported, replace the
hardcoded suffix list with a generator that can produce enough unique names
before calling `addProject`.
In `@backend/data/src/main/kotlin/io/tolgee/model/Project.kt`:
- Line 175: Rename the Project property currently named public to a more
idiomatic boolean name like isPublic so it does not read like the Kotlin
visibility keyword and is clearer at call sites. Update the Project class
property definition and any usages/accessors in the diff to match the new name,
while keeping the existing database mapping intact via the current column
annotation.
In `@e2e/cypress/e2e/projects/communityProjectsNavigation.cy.ts`:
- Around line 195-209: The community projects navigation spec is using
text-based assertions instead of stable E2E selectors. Update the checks in
communityProjectsNavigation.cy.ts to use data-cy via gcy()/cy.gcy() for the
project items and badge visibility, and avoid cy.contains for “Community Alpha”,
“Community Zeta”, and “Private project”. Keep the existing test intent in the
affected it blocks, but reference the same selector helpers already used in this
file such as gcy('dashboard-projects-list-item'),
gcy('project-list-public-badge'), and gcy('global-list-search').
- Around line 78-106: The Cypress assertions in
communityProjectsNavigation.cy.ts are still using text-based chaining on gcy
selectors, which violates the data-cy-only selector rule. Update the affected
checks in the community switcher and Projects title tests to target nested
data-cy elements instead of contains text, using the existing gcy and findDcy
patterns around organization-switch and global-base-view-title so the assertions
rely only on data-cy attributes.
In `@e2e/cypress/e2e/projects/suggestions/suggestions.reviewer.cy.ts`:
- Around line 268-291: The row-targeting helpers acceptOnly and openRowMenu rely
on translated text via .contains(text), which makes the tests fragile. Update
these helpers and the related callers in suggestions.reviewer.cy.ts to target
each translation-suggestion row using a stable data-cy-based identifier instead
of visible copy, ideally by adding a per-row value such as a suggestion id/index
and selecting it through cy.gcy() or gcyAdvanced(). Keep the action clicks the
same, but remove text matching so the suite no longer depends on suggestion
phrasing or i18n.
In
`@ee/backend/app/src/main/kotlin/io/tolgee/ee/api/v2/controllers/SuggestionController.kt`:
- Around line 142-150: The PermissionException handling in
SuggestionController.checkLanguageSuggestionsManagePermission currently rethrows
a new exception and loses the original cause; update this catch block to
preserve the underlying exception by using a cause-aware path (for example via
ExceptionWithMessage) or by avoiding the rewrap entirely. Keep the existing
special handling for LanguageNotPermittedException, and adjust the
PermissionException branch so the original throwable is carried forward while
still mapping to Message.USER_CAN_ONLY_DELETE_HIS_SUGGESTIONS.
In `@webapp/src/component/SwitchPopover/SwitchPopover.tsx`:
- Around line 88-93: Make footerAction.dataCy required in SwitchPopover’s
footerAction type so every action has a Cypress selector. Update the
footerAction interface and any related props/usage in SwitchPopover and the
affected call sites so they always pass a dataCy value. Use the footerAction
symbol and any rendering logic that wires the selector to the footer action
button to keep E2E testability guaranteed.
In `@webapp/src/views/projects/translations/context/services/useEditService.tsx`:
- Line 20: The import in useEditService should use the tg.views alias instead of
a cross-directory relative path. Update the MAX_DISPLAYED_SUGGESTIONS import to
point through the views alias so it follows the project’s Tolgee path-alias
convention and avoids relative imports across directories.
In
`@webapp/src/views/projects/translations/Suggestions/TranslationSuggestion.tsx`:
- Around line 131-172: The new translation keys used in TranslationSuggestion
are missing required default text. Update the calls in TranslationSuggestion so
the t() lookups for translation_suggestion_accept_only and
translation_suggestion_accept_and_decline_others include defaultValue strings,
alongside the existing translation_suggestion_accept_tooltip and
translation_suggestion_reverse_tooltip usages, so the labels remain meaningful
before Tolgee sync.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 26edd629-e21a-4c7b-8ccd-f005a3082d26
⛔ Files ignored due to path filters (1)
webapp/public/images/communityMouse.svgis excluded by!**/*.svg
📒 Files selected for processing (132)
backend/api/src/main/kotlin/io/tolgee/api/v2/controllers/ApiKeyController.ktbackend/api/src/main/kotlin/io/tolgee/api/v2/controllers/ProjectStatsController.ktbackend/api/src/main/kotlin/io/tolgee/api/v2/controllers/dataImport/ImportSettingsController.ktbackend/api/src/main/kotlin/io/tolgee/api/v2/controllers/machineTranslation/MtCreditsController.ktbackend/api/src/main/kotlin/io/tolgee/api/v2/controllers/project/ProjectsPublishingController.ktbackend/api/src/main/kotlin/io/tolgee/api/v2/controllers/project/PublicProjectsController.ktbackend/api/src/main/kotlin/io/tolgee/hateoas/activity/ProjectActivityModelAssembler.ktbackend/api/src/main/kotlin/io/tolgee/hateoas/apiKey/ApiKeyPermissionsModel.ktbackend/api/src/main/kotlin/io/tolgee/hateoas/key/trash/TrashedKeyModelAssembler.ktbackend/api/src/main/kotlin/io/tolgee/hateoas/key/trash/TrashedKeyWithTranslationsModelAssembler.ktbackend/api/src/main/kotlin/io/tolgee/hateoas/permission/IPermissionModel.ktbackend/api/src/main/kotlin/io/tolgee/hateoas/permission/PermissionModel.ktbackend/api/src/main/kotlin/io/tolgee/hateoas/permission/PermissionModelAssembler.ktbackend/api/src/main/kotlin/io/tolgee/hateoas/permission/PermissionWithAgencyModel.ktbackend/api/src/main/kotlin/io/tolgee/hateoas/permission/PermissionWithAgencyModelAssembler.ktbackend/api/src/main/kotlin/io/tolgee/hateoas/project/ProjectModel.ktbackend/api/src/main/kotlin/io/tolgee/hateoas/project/ProjectModelAssembler.ktbackend/api/src/main/kotlin/io/tolgee/hateoas/project/ProjectWithStatsModel.ktbackend/api/src/main/kotlin/io/tolgee/hateoas/project/ProjectWithStatsModelAssembler.ktbackend/api/src/main/kotlin/io/tolgee/hateoas/translations/TranslationHistoryModelAssembler.ktbackend/api/src/main/kotlin/io/tolgee/hateoas/translations/suggestions/TranslationSuggestionSimpleModelAssembler.ktbackend/api/src/main/kotlin/io/tolgee/hateoas/userAccount/SimpleUserAccountModelAssembler.ktbackend/api/src/main/kotlin/io/tolgee/hateoas/userAccount/UserAccountInProjectModelAssembler.ktbackend/api/src/main/kotlin/io/tolgee/websocket/ActivityWebsocketListener.ktbackend/app/src/main/kotlin/io/tolgee/configuration/WebSecurityConfig.ktbackend/app/src/test/kotlin/io/tolgee/api/v2/controllers/CommunityPermissionComputationTest.ktbackend/app/src/test/kotlin/io/tolgee/api/v2/controllers/CommunityPermissionTest.ktbackend/app/src/test/kotlin/io/tolgee/api/v2/controllers/ProjectStatsControllerTest.ktbackend/app/src/test/kotlin/io/tolgee/api/v2/controllers/PublicProjectsControllerTest.ktbackend/app/src/test/kotlin/io/tolgee/api/v2/controllers/notification/NotificationControllerTest.ktbackend/app/src/test/kotlin/io/tolgee/api/v2/controllers/organizationController/OrganizationProjectsControllerTest.ktbackend/app/src/test/kotlin/io/tolgee/api/v2/controllers/translations/v2TranslationsController/TranslationsControllerFilterTest.ktbackend/app/src/test/kotlin/io/tolgee/api/v2/controllers/v2ProjectsController/ProjectsControllerPublishingTest.ktbackend/app/src/test/kotlin/io/tolgee/service/LanguageDeletePermissionTest.ktbackend/app/src/test/kotlin/io/tolgee/service/ProjectPublishingCachingTest.ktbackend/app/src/test/kotlin/io/tolgee/websocket/AbstractWebsocketTest.ktbackend/data/src/main/kotlin/io/tolgee/constants/ComputedPermissionOrigin.ktbackend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/LanguagePermissionsTestData.ktbackend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/ProjectPublishingTestData.ktbackend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/ProjectsListDashboardTestData.ktbackend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/ProjectsTestData.ktbackend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/PublicProjectsControllerTestData.ktbackend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/PublicProjectsE2eData.ktbackend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/PublicProjectsStatsTestData.ktbackend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/SuggestionsTestData.ktbackend/data/src/main/kotlin/io/tolgee/dtos/ComputedPermissionDto.ktbackend/data/src/main/kotlin/io/tolgee/dtos/cacheable/IPermission.ktbackend/data/src/main/kotlin/io/tolgee/dtos/cacheable/PermissionDto.ktbackend/data/src/main/kotlin/io/tolgee/dtos/cacheable/ProjectDto.ktbackend/data/src/main/kotlin/io/tolgee/dtos/queryResults/organization/BasePermissionView.ktbackend/data/src/main/kotlin/io/tolgee/dtos/request/project/LanguagePermissions.ktbackend/data/src/main/kotlin/io/tolgee/dtos/request/project/ProjectInviteUserDto.ktbackend/data/src/main/kotlin/io/tolgee/dtos/request/project/RequestWithLanguagePermissions.ktbackend/data/src/main/kotlin/io/tolgee/dtos/request/project/SetPermissionLanguageParams.ktbackend/data/src/main/kotlin/io/tolgee/dtos/request/project/SetProjectPublicRequest.ktbackend/data/src/main/kotlin/io/tolgee/facade/ProjectPermissionFacade.ktbackend/data/src/main/kotlin/io/tolgee/model/Permission.ktbackend/data/src/main/kotlin/io/tolgee/model/Project.ktbackend/data/src/main/kotlin/io/tolgee/model/enums/ProjectPermissionType.ktbackend/data/src/main/kotlin/io/tolgee/model/enums/Scope.ktbackend/data/src/main/kotlin/io/tolgee/model/views/ProjectView.ktbackend/data/src/main/kotlin/io/tolgee/model/views/ProjectWithLanguagesView.ktbackend/data/src/main/kotlin/io/tolgee/model/views/ProjectWithStatsView.ktbackend/data/src/main/kotlin/io/tolgee/repository/PermissionRepository.ktbackend/data/src/main/kotlin/io/tolgee/repository/ProjectRepository.ktbackend/data/src/main/kotlin/io/tolgee/service/CachedPermissionService.ktbackend/data/src/main/kotlin/io/tolgee/service/project/ProjectService.ktbackend/data/src/main/kotlin/io/tolgee/service/security/LanguageDeletedPermissionUpdater.ktbackend/data/src/main/kotlin/io/tolgee/service/security/PermissionService.ktbackend/data/src/main/kotlin/io/tolgee/service/security/SecurityService.ktbackend/data/src/main/resources/db/changelog/schema.xmlbackend/data/src/test/kotlin/io/tolgee/unit/CommunityPermissionScopesTest.ktbackend/data/src/test/kotlin/io/tolgee/unit/MemberInfoMaskingTest.ktbackend/development/src/main/kotlin/io/tolgee/controllers/internal/e2eData/ProjectListDashboardE2eDataController.ktbackend/development/src/main/kotlin/io/tolgee/controllers/internal/e2eData/PublicProjectsE2eDataController.kte2e/cypress/common/apiCalls/testData/testData.tse2e/cypress/e2e/administration/base.cy.tse2e/cypress/e2e/projects/communityProjectsNavigation.cy.tse2e/cypress/e2e/projects/projectsListDashboard.cy.tse2e/cypress/e2e/projects/publicProjects.cy.tse2e/cypress/e2e/projects/settings.public.cy.tse2e/cypress/e2e/projects/suggestions/suggestions.reviewer.cy.tse2e/cypress/e2e/projects/suggestions/suggestions.translator.cy.tse2e/cypress/e2e/projects/suggestions/suggestions.unprotected.cy.tse2e/cypress/e2e/translations/translationFilters.suggestions.cy.tse2e/cypress/support/dataCyType.d.tsee/backend/app/src/main/kotlin/io/tolgee/ee/api/v2/controllers/SuggestionController.ktee/backend/app/src/main/kotlin/io/tolgee/ee/api/v2/controllers/TaskController.ktee/backend/app/src/main/kotlin/io/tolgee/ee/api/v2/controllers/branching/BranchController.ktee/backend/app/src/main/kotlin/io/tolgee/ee/repository/TranslationSuggestionRepository.ktee/backend/app/src/main/kotlin/io/tolgee/ee/service/TranslationSuggestionServiceEeImpl.ktee/backend/tests/src/test/kotlin/io/tolgee/ee/api/v2/controllers/AdvancedPermissionControllerTest.ktee/backend/tests/src/test/kotlin/io/tolgee/ee/api/v2/controllers/CommunitySuggestionTest.ktee/backend/tests/src/test/kotlin/io/tolgee/ee/api/v2/controllers/SuggestionControllerTest.ktee/backend/tests/src/test/kotlin/io/tolgee/ee/api/v2/controllers/task/TaskControllerPermissionsTest.ktee/backend/tests/src/test/kotlin/io/tolgee/ee/api/v2/controllers/task/TaskControllerTest.ktwebapp/src/component/PermissionsSettings/LanguagePermissionsSummary.tsxwebapp/src/component/PermissionsSettings/PermissionsSettings.tsxwebapp/src/component/PermissionsSettings/hierarchyTools.tswebapp/src/component/PermissionsSettings/usePermissionsStructure.tswebapp/src/component/PermissionsSettings/useScopeTranslations.tsxwebapp/src/component/RootRouter.tsxwebapp/src/component/SwitchPopover/SwitchPopover.tsxwebapp/src/component/layout/BaseView.tsxwebapp/src/component/layout/HeaderBar.tsxwebapp/src/component/organizationSwitch/CommunityTranslationItem.tsxwebapp/src/component/organizationSwitch/OrganizationPopover.tsxwebapp/src/component/organizationSwitch/OrganizationSwitch.tsxwebapp/src/constants/links.tsxwebapp/src/fixtures/permissions.tswebapp/src/service/apiSchema.generated.tswebapp/src/service/apiSchemaTypes.generated.tswebapp/src/views/projects/CommunityProjectsView.tsxwebapp/src/views/projects/DashboardProjectListItem.tsxwebapp/src/views/projects/ProjectListView.tsxwebapp/src/views/projects/ProjectsList.tsxwebapp/src/views/projects/dashboard/ProjectTotals.tsxwebapp/src/views/projects/project/ProjectSettingsAdvanced.tsxwebapp/src/views/projects/public/CommunityTranslationBanner.tsxwebapp/src/views/projects/public/PublicProjectListView.tsxwebapp/src/views/projects/public/PublicTopBar.tsxwebapp/src/views/projects/public/publicProjectsLayout.tswebapp/src/views/projects/translations/Suggestions/SuggestionsFirst.tsxwebapp/src/views/projects/translations/Suggestions/SuggestionsList.tsxwebapp/src/views/projects/translations/Suggestions/TranslationSuggestion.tsxwebapp/src/views/projects/translations/Suggestions/__tests__/utils.test.tswebapp/src/views/projects/translations/Suggestions/useInfiniteSuggestions.tswebapp/src/views/projects/translations/Suggestions/utils.tswebapp/src/views/projects/translations/TranslationsList/TranslationRead.tsxwebapp/src/views/projects/translations/TranslationsTable/TranslationRead.tsxwebapp/src/views/projects/translations/context/services/useEditService.tsxwebapp/src/views/projects/useLatchedSearchVisibility.ts
ec88b34 to
5153a35
Compare
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@backend/api/src/main/kotlin/io/tolgee/api/v2/controllers/project/ProjectsPublishingController.kt`:
- Around line 21-29: The publishing controller currently applies wildcard CORS
at the class level, which is too broad for the authenticated project-visibility
update endpoint. Remove the `@CrossOrigin(origins = ["*"])` from
`ProjectsPublishingController` and rely on the app’s shared CORS configuration,
or replace it with a narrowly scoped origin list if this endpoint truly needs
its own setting. Keep the change localized to `ProjectsPublishingController` so
the `PUT` publishing action remains protected by trusted-origin rules.
In
`@ee/backend/app/src/main/kotlin/io/tolgee/ee/api/v2/controllers/SuggestionController.kt`:
- Around line 117-119: The OpenAPI description for
SuggestionController.deleteSuggestion is missing the updated delete
authorization rule, so the docs are now ambiguous. Update the `@Operation`
summary/description on deleteSuggestion in SuggestionController to explicitly
state that deletion is allowed either by the suggestion author or by users with
suggestion-management permission, keeping the API docs aligned with the actual
authorization behavior.
- Around line 148-149: The PermissionException handling in
SuggestionController’s delete flow is dropping the original cause by rethrowing
only a new message. Update the catch block to preserve the caught
PermissionException as the cause, either by using an existing cause-aware
constructor or by adding one to PermissionException, so the original failure is
retained when rethrown.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: ea2f1c9a-9973-4756-8e38-8d202a37539b
⛔ Files ignored due to path filters (1)
webapp/public/images/communityMouse.svgis excluded by!**/*.svg
📒 Files selected for processing (133)
backend/api/src/main/kotlin/io/tolgee/api/v2/controllers/ApiKeyController.ktbackend/api/src/main/kotlin/io/tolgee/api/v2/controllers/ProjectStatsController.ktbackend/api/src/main/kotlin/io/tolgee/api/v2/controllers/dataImport/ImportSettingsController.ktbackend/api/src/main/kotlin/io/tolgee/api/v2/controllers/machineTranslation/MtCreditsController.ktbackend/api/src/main/kotlin/io/tolgee/api/v2/controllers/project/ProjectsPublishingController.ktbackend/api/src/main/kotlin/io/tolgee/api/v2/controllers/project/PublicProjectsController.ktbackend/api/src/main/kotlin/io/tolgee/hateoas/activity/ProjectActivityModelAssembler.ktbackend/api/src/main/kotlin/io/tolgee/hateoas/apiKey/ApiKeyPermissionsModel.ktbackend/api/src/main/kotlin/io/tolgee/hateoas/key/trash/TrashedKeyModelAssembler.ktbackend/api/src/main/kotlin/io/tolgee/hateoas/key/trash/TrashedKeyWithTranslationsModelAssembler.ktbackend/api/src/main/kotlin/io/tolgee/hateoas/permission/IPermissionModel.ktbackend/api/src/main/kotlin/io/tolgee/hateoas/permission/PermissionModel.ktbackend/api/src/main/kotlin/io/tolgee/hateoas/permission/PermissionModelAssembler.ktbackend/api/src/main/kotlin/io/tolgee/hateoas/permission/PermissionWithAgencyModel.ktbackend/api/src/main/kotlin/io/tolgee/hateoas/permission/PermissionWithAgencyModelAssembler.ktbackend/api/src/main/kotlin/io/tolgee/hateoas/project/ProjectModel.ktbackend/api/src/main/kotlin/io/tolgee/hateoas/project/ProjectModelAssembler.ktbackend/api/src/main/kotlin/io/tolgee/hateoas/project/ProjectWithStatsModel.ktbackend/api/src/main/kotlin/io/tolgee/hateoas/project/ProjectWithStatsModelAssembler.ktbackend/api/src/main/kotlin/io/tolgee/hateoas/translations/TranslationHistoryModelAssembler.ktbackend/api/src/main/kotlin/io/tolgee/hateoas/translations/suggestions/TranslationSuggestionSimpleModelAssembler.ktbackend/api/src/main/kotlin/io/tolgee/hateoas/userAccount/SimpleUserAccountModelAssembler.ktbackend/api/src/main/kotlin/io/tolgee/hateoas/userAccount/UserAccountInProjectModelAssembler.ktbackend/api/src/main/kotlin/io/tolgee/websocket/ActivityWebsocketListener.ktbackend/app/src/main/kotlin/io/tolgee/configuration/WebSecurityConfig.ktbackend/app/src/test/kotlin/io/tolgee/api/v2/controllers/CommunityPermissionComputationTest.ktbackend/app/src/test/kotlin/io/tolgee/api/v2/controllers/CommunityPermissionTest.ktbackend/app/src/test/kotlin/io/tolgee/api/v2/controllers/ProjectStatsControllerTest.ktbackend/app/src/test/kotlin/io/tolgee/api/v2/controllers/PublicProjectsControllerTest.ktbackend/app/src/test/kotlin/io/tolgee/api/v2/controllers/notification/NotificationControllerTest.ktbackend/app/src/test/kotlin/io/tolgee/api/v2/controllers/organizationController/OrganizationProjectsControllerTest.ktbackend/app/src/test/kotlin/io/tolgee/api/v2/controllers/translations/v2TranslationsController/TranslationsControllerFilterTest.ktbackend/app/src/test/kotlin/io/tolgee/api/v2/controllers/v2ProjectsController/ProjectsControllerPublishingTest.ktbackend/app/src/test/kotlin/io/tolgee/service/LanguageDeletePermissionTest.ktbackend/app/src/test/kotlin/io/tolgee/service/ProjectPublishingCachingTest.ktbackend/app/src/test/kotlin/io/tolgee/websocket/AbstractWebsocketTest.ktbackend/data/src/main/kotlin/io/tolgee/constants/ComputedPermissionOrigin.ktbackend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/LanguagePermissionsTestData.ktbackend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/ProjectPublishingTestData.ktbackend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/ProjectsListDashboardTestData.ktbackend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/ProjectsTestData.ktbackend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/PublicProjectsControllerTestData.ktbackend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/PublicProjectsE2eData.ktbackend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/PublicProjectsStatsTestData.ktbackend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/SuggestionsTestData.ktbackend/data/src/main/kotlin/io/tolgee/dtos/ComputedPermissionDto.ktbackend/data/src/main/kotlin/io/tolgee/dtos/cacheable/IPermission.ktbackend/data/src/main/kotlin/io/tolgee/dtos/cacheable/PermissionDto.ktbackend/data/src/main/kotlin/io/tolgee/dtos/cacheable/ProjectDto.ktbackend/data/src/main/kotlin/io/tolgee/dtos/queryResults/organization/BasePermissionView.ktbackend/data/src/main/kotlin/io/tolgee/dtos/request/project/LanguagePermissions.ktbackend/data/src/main/kotlin/io/tolgee/dtos/request/project/ProjectInviteUserDto.ktbackend/data/src/main/kotlin/io/tolgee/dtos/request/project/RequestWithLanguagePermissions.ktbackend/data/src/main/kotlin/io/tolgee/dtos/request/project/SetPermissionLanguageParams.ktbackend/data/src/main/kotlin/io/tolgee/dtos/request/project/SetProjectPublicRequest.ktbackend/data/src/main/kotlin/io/tolgee/facade/ProjectPermissionFacade.ktbackend/data/src/main/kotlin/io/tolgee/model/Permission.ktbackend/data/src/main/kotlin/io/tolgee/model/Project.ktbackend/data/src/main/kotlin/io/tolgee/model/enums/ProjectPermissionType.ktbackend/data/src/main/kotlin/io/tolgee/model/enums/Scope.ktbackend/data/src/main/kotlin/io/tolgee/model/views/ProjectView.ktbackend/data/src/main/kotlin/io/tolgee/model/views/ProjectWithLanguagesView.ktbackend/data/src/main/kotlin/io/tolgee/model/views/ProjectWithStatsView.ktbackend/data/src/main/kotlin/io/tolgee/repository/PermissionRepository.ktbackend/data/src/main/kotlin/io/tolgee/repository/ProjectRepository.ktbackend/data/src/main/kotlin/io/tolgee/service/CachedPermissionService.ktbackend/data/src/main/kotlin/io/tolgee/service/project/ProjectService.ktbackend/data/src/main/kotlin/io/tolgee/service/security/LanguageDeletedPermissionUpdater.ktbackend/data/src/main/kotlin/io/tolgee/service/security/PermissionService.ktbackend/data/src/main/kotlin/io/tolgee/service/security/SecurityService.ktbackend/data/src/main/resources/db/changelog/schema.xmlbackend/data/src/test/kotlin/io/tolgee/unit/CommunityPermissionScopesTest.ktbackend/data/src/test/kotlin/io/tolgee/unit/MemberInfoMaskingTest.ktbackend/data/src/test/kotlin/io/tolgee/unit/PermissionOrgBaseLanguageGuardTest.ktbackend/development/src/main/kotlin/io/tolgee/controllers/internal/e2eData/ProjectListDashboardE2eDataController.ktbackend/development/src/main/kotlin/io/tolgee/controllers/internal/e2eData/PublicProjectsE2eDataController.kte2e/cypress/common/apiCalls/testData/testData.tse2e/cypress/e2e/administration/base.cy.tse2e/cypress/e2e/projects/communityProjectsNavigation.cy.tse2e/cypress/e2e/projects/projectsListDashboard.cy.tse2e/cypress/e2e/projects/publicProjects.cy.tse2e/cypress/e2e/projects/settings.public.cy.tse2e/cypress/e2e/projects/suggestions/suggestions.reviewer.cy.tse2e/cypress/e2e/projects/suggestions/suggestions.translator.cy.tse2e/cypress/e2e/projects/suggestions/suggestions.unprotected.cy.tse2e/cypress/e2e/translations/translationFilters.suggestions.cy.tse2e/cypress/support/dataCyType.d.tsee/backend/app/src/main/kotlin/io/tolgee/ee/api/v2/controllers/SuggestionController.ktee/backend/app/src/main/kotlin/io/tolgee/ee/api/v2/controllers/TaskController.ktee/backend/app/src/main/kotlin/io/tolgee/ee/api/v2/controllers/branching/BranchController.ktee/backend/app/src/main/kotlin/io/tolgee/ee/repository/TranslationSuggestionRepository.ktee/backend/app/src/main/kotlin/io/tolgee/ee/service/TranslationSuggestionServiceEeImpl.ktee/backend/tests/src/test/kotlin/io/tolgee/ee/api/v2/controllers/AdvancedPermissionControllerTest.ktee/backend/tests/src/test/kotlin/io/tolgee/ee/api/v2/controllers/CommunitySuggestionTest.ktee/backend/tests/src/test/kotlin/io/tolgee/ee/api/v2/controllers/SuggestionControllerTest.ktee/backend/tests/src/test/kotlin/io/tolgee/ee/api/v2/controllers/task/TaskControllerPermissionsTest.ktee/backend/tests/src/test/kotlin/io/tolgee/ee/api/v2/controllers/task/TaskControllerTest.ktwebapp/src/component/PermissionsSettings/LanguagePermissionsSummary.tsxwebapp/src/component/PermissionsSettings/PermissionsSettings.tsxwebapp/src/component/PermissionsSettings/hierarchyTools.tswebapp/src/component/PermissionsSettings/usePermissionsStructure.tswebapp/src/component/PermissionsSettings/useScopeTranslations.tsxwebapp/src/component/RootRouter.tsxwebapp/src/component/SwitchPopover/SwitchPopover.tsxwebapp/src/component/layout/BaseView.tsxwebapp/src/component/layout/HeaderBar.tsxwebapp/src/component/organizationSwitch/CommunityTranslationItem.tsxwebapp/src/component/organizationSwitch/OrganizationPopover.tsxwebapp/src/component/organizationSwitch/OrganizationSwitch.tsxwebapp/src/constants/links.tsxwebapp/src/fixtures/permissions.tswebapp/src/service/apiSchema.generated.tswebapp/src/service/apiSchemaTypes.generated.tswebapp/src/views/projects/CommunityProjectsView.tsxwebapp/src/views/projects/DashboardProjectListItem.tsxwebapp/src/views/projects/ProjectListView.tsxwebapp/src/views/projects/ProjectsList.tsxwebapp/src/views/projects/dashboard/ProjectTotals.tsxwebapp/src/views/projects/project/ProjectSettingsAdvanced.tsxwebapp/src/views/projects/public/CommunityTranslationBanner.tsxwebapp/src/views/projects/public/PublicProjectListView.tsxwebapp/src/views/projects/public/PublicTopBar.tsxwebapp/src/views/projects/public/publicProjectsLayout.tswebapp/src/views/projects/translations/Suggestions/SuggestionsFirst.tsxwebapp/src/views/projects/translations/Suggestions/SuggestionsList.tsxwebapp/src/views/projects/translations/Suggestions/TranslationSuggestion.tsxwebapp/src/views/projects/translations/Suggestions/__tests__/utils.test.tswebapp/src/views/projects/translations/Suggestions/useInfiniteSuggestions.tswebapp/src/views/projects/translations/Suggestions/utils.tswebapp/src/views/projects/translations/TranslationsList/TranslationRead.tsxwebapp/src/views/projects/translations/TranslationsTable/TranslationRead.tsxwebapp/src/views/projects/translations/context/services/useEditService.tsxwebapp/src/views/projects/useLatchedSearchVisibility.ts
✅ Files skipped from review due to trivial changes (9)
- webapp/src/views/projects/public/publicProjectsLayout.ts
- backend/api/src/main/kotlin/io/tolgee/hateoas/project/ProjectModel.kt
- backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/ProjectsListDashboardTestData.kt
- backend/api/src/main/kotlin/io/tolgee/hateoas/userAccount/UserAccountInProjectModelAssembler.kt
- webapp/src/component/layout/BaseView.tsx
- backend/data/src/main/kotlin/io/tolgee/facade/ProjectPermissionFacade.kt
- ee/backend/tests/src/test/kotlin/io/tolgee/ee/api/v2/controllers/task/TaskControllerPermissionsTest.kt
- webapp/src/service/apiSchemaTypes.generated.ts
- e2e/cypress/support/dataCyType.d.ts
🚧 Files skipped from review as they are similar to previous changes (116)
- backend/data/src/main/kotlin/io/tolgee/dtos/cacheable/IPermission.kt
- webapp/src/views/projects/translations/Suggestions/useInfiniteSuggestions.ts
- webapp/src/component/organizationSwitch/CommunityTranslationItem.tsx
- backend/data/src/main/kotlin/io/tolgee/dtos/request/project/SetProjectPublicRequest.kt
- webapp/src/component/PermissionsSettings/useScopeTranslations.tsx
- backend/data/src/main/kotlin/io/tolgee/model/views/ProjectView.kt
- webapp/src/views/projects/useLatchedSearchVisibility.ts
- backend/api/src/main/kotlin/io/tolgee/hateoas/permission/PermissionWithAgencyModel.kt
- backend/data/src/main/kotlin/io/tolgee/dtos/request/project/ProjectInviteUserDto.kt
- backend/api/src/main/kotlin/io/tolgee/hateoas/translations/TranslationHistoryModelAssembler.kt
- e2e/cypress/e2e/projects/suggestions/suggestions.unprotected.cy.ts
- backend/data/src/main/kotlin/io/tolgee/constants/ComputedPermissionOrigin.kt
- backend/data/src/main/kotlin/io/tolgee/service/CachedPermissionService.kt
- backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/PublicProjectsE2eData.kt
- backend/api/src/main/kotlin/io/tolgee/hateoas/permission/PermissionModelAssembler.kt
- backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/PublicProjectsStatsTestData.kt
- backend/api/src/main/kotlin/io/tolgee/api/v2/controllers/ApiKeyController.kt
- backend/data/src/main/kotlin/io/tolgee/model/views/ProjectWithLanguagesView.kt
- backend/app/src/test/kotlin/io/tolgee/websocket/AbstractWebsocketTest.kt
- backend/data/src/main/kotlin/io/tolgee/dtos/request/project/SetPermissionLanguageParams.kt
- webapp/src/component/PermissionsSettings/LanguagePermissionsSummary.tsx
- backend/api/src/main/kotlin/io/tolgee/api/v2/controllers/machineTranslation/MtCreditsController.kt
- backend/data/src/main/kotlin/io/tolgee/dtos/cacheable/ProjectDto.kt
- ee/backend/tests/src/test/kotlin/io/tolgee/ee/api/v2/controllers/task/TaskControllerTest.kt
- backend/api/src/main/kotlin/io/tolgee/hateoas/apiKey/ApiKeyPermissionsModel.kt
- webapp/src/fixtures/permissions.ts
- webapp/src/views/projects/public/PublicTopBar.tsx
- backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/ProjectsTestData.kt
- webapp/src/constants/links.tsx
- backend/data/src/main/kotlin/io/tolgee/dtos/cacheable/PermissionDto.kt
- backend/data/src/main/kotlin/io/tolgee/dtos/request/project/RequestWithLanguagePermissions.kt
- webapp/src/component/RootRouter.tsx
- backend/api/src/main/kotlin/io/tolgee/hateoas/userAccount/SimpleUserAccountModelAssembler.kt
- webapp/src/views/projects/ProjectsList.tsx
- backend/data/src/main/kotlin/io/tolgee/model/Project.kt
- webapp/src/component/PermissionsSettings/usePermissionsStructure.ts
- backend/data/src/main/kotlin/io/tolgee/repository/PermissionRepository.kt
- backend/api/src/main/kotlin/io/tolgee/hateoas/permission/IPermissionModel.kt
- backend/api/src/main/kotlin/io/tolgee/hateoas/translations/suggestions/TranslationSuggestionSimpleModelAssembler.kt
- backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/ProjectPublishingTestData.kt
- webapp/src/views/projects/dashboard/ProjectTotals.tsx
- backend/api/src/main/kotlin/io/tolgee/websocket/ActivityWebsocketListener.kt
- backend/api/src/main/kotlin/io/tolgee/hateoas/key/trash/TrashedKeyWithTranslationsModelAssembler.kt
- webapp/src/views/projects/translations/Suggestions/utils.ts
- backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/organizationController/OrganizationProjectsControllerTest.kt
- backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/PublicProjectsControllerTestData.kt
- webapp/src/views/projects/translations/TranslationsList/TranslationRead.tsx
- backend/app/src/main/kotlin/io/tolgee/configuration/WebSecurityConfig.kt
- backend/data/src/main/kotlin/io/tolgee/dtos/request/project/LanguagePermissions.kt
- backend/app/src/test/kotlin/io/tolgee/service/ProjectPublishingCachingTest.kt
- backend/data/src/main/kotlin/io/tolgee/model/enums/ProjectPermissionType.kt
- e2e/cypress/e2e/translations/translationFilters.suggestions.cy.ts
- webapp/src/views/projects/translations/TranslationsTable/TranslationRead.tsx
- backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/notification/NotificationControllerTest.kt
- e2e/cypress/e2e/projects/projectsListDashboard.cy.ts
- backend/api/src/main/kotlin/io/tolgee/hateoas/permission/PermissionModel.kt
- backend/api/src/main/kotlin/io/tolgee/hateoas/project/ProjectModelAssembler.kt
- backend/api/src/main/kotlin/io/tolgee/hateoas/key/trash/TrashedKeyModelAssembler.kt
- e2e/cypress/e2e/administration/base.cy.ts
- backend/api/src/main/kotlin/io/tolgee/hateoas/project/ProjectWithStatsModel.kt
- webapp/src/views/projects/ProjectListView.tsx
- webapp/src/views/projects/translations/Suggestions/SuggestionsFirst.tsx
- backend/development/src/main/kotlin/io/tolgee/controllers/internal/e2eData/ProjectListDashboardE2eDataController.kt
- e2e/cypress/e2e/projects/suggestions/suggestions.translator.cy.ts
- webapp/src/views/projects/translations/context/services/useEditService.tsx
- backend/data/src/main/kotlin/io/tolgee/model/views/ProjectWithStatsView.kt
- backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/ProjectStatsControllerTest.kt
- backend/data/src/main/resources/db/changelog/schema.xml
- backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/v2ProjectsController/ProjectsControllerPublishingTest.kt
- backend/api/src/main/kotlin/io/tolgee/api/v2/controllers/ProjectStatsController.kt
- webapp/src/views/projects/translations/Suggestions/tests/utils.test.ts
- backend/api/src/main/kotlin/io/tolgee/hateoas/activity/ProjectActivityModelAssembler.kt
- ee/backend/tests/src/test/kotlin/io/tolgee/ee/api/v2/controllers/AdvancedPermissionControllerTest.kt
- webapp/src/views/projects/public/CommunityTranslationBanner.tsx
- ee/backend/app/src/main/kotlin/io/tolgee/ee/api/v2/controllers/branching/BranchController.kt
- e2e/cypress/e2e/projects/settings.public.cy.ts
- e2e/cypress/common/apiCalls/testData/testData.ts
- ee/backend/tests/src/test/kotlin/io/tolgee/ee/api/v2/controllers/CommunitySuggestionTest.kt
- webapp/src/views/projects/project/ProjectSettingsAdvanced.tsx
- webapp/src/component/PermissionsSettings/hierarchyTools.ts
- backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/CommunityPermissionComputationTest.kt
- backend/data/src/main/kotlin/io/tolgee/dtos/queryResults/organization/BasePermissionView.kt
- webapp/src/component/SwitchPopover/SwitchPopover.tsx
- webapp/src/component/PermissionsSettings/PermissionsSettings.tsx
- ee/backend/app/src/main/kotlin/io/tolgee/ee/repository/TranslationSuggestionRepository.kt
- webapp/src/views/projects/public/PublicProjectListView.tsx
- backend/api/src/main/kotlin/io/tolgee/api/v2/controllers/project/PublicProjectsController.kt
- backend/data/src/main/kotlin/io/tolgee/model/enums/Scope.kt
- backend/data/src/main/kotlin/io/tolgee/repository/ProjectRepository.kt
- ee/backend/app/src/main/kotlin/io/tolgee/ee/api/v2/controllers/TaskController.kt
- webapp/src/views/projects/translations/Suggestions/TranslationSuggestion.tsx
- webapp/src/component/organizationSwitch/OrganizationPopover.tsx
- backend/api/src/main/kotlin/io/tolgee/hateoas/project/ProjectWithStatsModelAssembler.kt
- e2e/cypress/e2e/projects/publicProjects.cy.ts
- backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/PublicProjectsControllerTest.kt
- ee/backend/app/src/main/kotlin/io/tolgee/ee/service/TranslationSuggestionServiceEeImpl.kt
- e2e/cypress/e2e/projects/suggestions/suggestions.reviewer.cy.ts
- webapp/src/component/organizationSwitch/OrganizationSwitch.tsx
- backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/SuggestionsTestData.kt
- e2e/cypress/e2e/projects/communityProjectsNavigation.cy.ts
- webapp/src/views/projects/translations/Suggestions/SuggestionsList.tsx
- backend/data/src/test/kotlin/io/tolgee/unit/CommunityPermissionScopesTest.kt
- backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/translations/v2TranslationsController/TranslationsControllerFilterTest.kt
- backend/data/src/main/kotlin/io/tolgee/dtos/ComputedPermissionDto.kt
- backend/data/src/main/kotlin/io/tolgee/service/security/PermissionService.kt
- backend/data/src/main/kotlin/io/tolgee/service/project/ProjectService.kt
- backend/data/src/main/kotlin/io/tolgee/service/security/LanguageDeletedPermissionUpdater.kt
- backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/CommunityPermissionTest.kt
- backend/api/src/main/kotlin/io/tolgee/api/v2/controllers/dataImport/ImportSettingsController.kt
- backend/data/src/main/kotlin/io/tolgee/service/security/SecurityService.kt
- webapp/src/component/layout/HeaderBar.tsx
- backend/api/src/main/kotlin/io/tolgee/hateoas/permission/PermissionWithAgencyModelAssembler.kt
- ee/backend/tests/src/test/kotlin/io/tolgee/ee/api/v2/controllers/SuggestionControllerTest.kt
- webapp/src/service/apiSchema.generated.ts
- webapp/src/views/projects/CommunityProjectsView.tsx
- backend/data/src/test/kotlin/io/tolgee/unit/MemberInfoMaskingTest.kt
5153a35 to
cb9efc5
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@webapp/src/views/projects/public/PublicProjectListView.tsx`:
- Line 41: The translation calls in PublicProjectListView are missing
defaultValue, so add fallback text to the useWindowTitle(t(...)) call for
public_projects_window_title and to the T usage for public_projects_empty.
Update the existing i18n keys in PublicProjectListView so both the window title
and empty-state text render meaningful content before Tolgee translations are
available.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 7cf6cd31-290b-46ae-ba45-3052c7efc4b9
⛔ Files ignored due to path filters (1)
webapp/public/images/communityMouse.svgis excluded by!**/*.svg
📒 Files selected for processing (122)
backend/api/src/main/kotlin/io/tolgee/api/v2/controllers/ApiKeyController.ktbackend/api/src/main/kotlin/io/tolgee/api/v2/controllers/ProjectStatsController.ktbackend/api/src/main/kotlin/io/tolgee/api/v2/controllers/dataImport/ImportSettingsController.ktbackend/api/src/main/kotlin/io/tolgee/api/v2/controllers/machineTranslation/MtCreditsController.ktbackend/api/src/main/kotlin/io/tolgee/api/v2/controllers/project/ProjectsPublishingController.ktbackend/api/src/main/kotlin/io/tolgee/api/v2/controllers/project/PublicProjectsController.ktbackend/api/src/main/kotlin/io/tolgee/hateoas/activity/ProjectActivityModelAssembler.ktbackend/api/src/main/kotlin/io/tolgee/hateoas/apiKey/ApiKeyPermissionsModel.ktbackend/api/src/main/kotlin/io/tolgee/hateoas/key/trash/TrashedKeyModelAssembler.ktbackend/api/src/main/kotlin/io/tolgee/hateoas/key/trash/TrashedKeyWithTranslationsModelAssembler.ktbackend/api/src/main/kotlin/io/tolgee/hateoas/permission/IPermissionModel.ktbackend/api/src/main/kotlin/io/tolgee/hateoas/permission/PermissionModel.ktbackend/api/src/main/kotlin/io/tolgee/hateoas/permission/PermissionModelAssembler.ktbackend/api/src/main/kotlin/io/tolgee/hateoas/permission/PermissionWithAgencyModel.ktbackend/api/src/main/kotlin/io/tolgee/hateoas/permission/PermissionWithAgencyModelAssembler.ktbackend/api/src/main/kotlin/io/tolgee/hateoas/project/ProjectModelAssembler.ktbackend/api/src/main/kotlin/io/tolgee/hateoas/project/ProjectWithStatsModel.ktbackend/api/src/main/kotlin/io/tolgee/hateoas/project/ProjectWithStatsModelAssembler.ktbackend/api/src/main/kotlin/io/tolgee/hateoas/translations/TranslationHistoryModelAssembler.ktbackend/api/src/main/kotlin/io/tolgee/hateoas/translations/suggestions/TranslationSuggestionSimpleModelAssembler.ktbackend/api/src/main/kotlin/io/tolgee/hateoas/userAccount/SimpleUserAccountModelAssembler.ktbackend/api/src/main/kotlin/io/tolgee/hateoas/userAccount/UserAccountInProjectModelAssembler.ktbackend/api/src/main/kotlin/io/tolgee/websocket/ActivityWebsocketListener.ktbackend/app/src/main/kotlin/io/tolgee/configuration/WebSecurityConfig.ktbackend/app/src/test/kotlin/io/tolgee/api/v2/controllers/CommunityPermissionComputationTest.ktbackend/app/src/test/kotlin/io/tolgee/api/v2/controllers/CommunityPermissionTest.ktbackend/app/src/test/kotlin/io/tolgee/api/v2/controllers/ProjectStatsControllerTest.ktbackend/app/src/test/kotlin/io/tolgee/api/v2/controllers/PublicProjectsControllerTest.ktbackend/app/src/test/kotlin/io/tolgee/api/v2/controllers/notification/NotificationControllerTest.ktbackend/app/src/test/kotlin/io/tolgee/api/v2/controllers/organizationController/OrganizationProjectsControllerTest.ktbackend/app/src/test/kotlin/io/tolgee/api/v2/controllers/translations/v2TranslationsController/TranslationsControllerFilterTest.ktbackend/app/src/test/kotlin/io/tolgee/service/LanguageDeletePermissionTest.ktbackend/app/src/test/kotlin/io/tolgee/websocket/AbstractWebsocketTest.ktbackend/data/src/main/kotlin/io/tolgee/constants/ComputedPermissionOrigin.ktbackend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/LanguagePermissionsTestData.ktbackend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/ProjectPublishingTestData.ktbackend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/ProjectsListDashboardTestData.ktbackend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/ProjectsTestData.ktbackend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/PublicProjectsControllerTestData.ktbackend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/PublicProjectsE2eData.ktbackend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/PublicProjectsStatsTestData.ktbackend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/SuggestionsTestData.ktbackend/data/src/main/kotlin/io/tolgee/dtos/ComputedPermissionDto.ktbackend/data/src/main/kotlin/io/tolgee/dtos/cacheable/IPermission.ktbackend/data/src/main/kotlin/io/tolgee/dtos/cacheable/PermissionDto.ktbackend/data/src/main/kotlin/io/tolgee/dtos/queryResults/organization/BasePermissionView.ktbackend/data/src/main/kotlin/io/tolgee/dtos/request/project/LanguagePermissions.ktbackend/data/src/main/kotlin/io/tolgee/dtos/request/project/ProjectInviteUserDto.ktbackend/data/src/main/kotlin/io/tolgee/dtos/request/project/RequestWithLanguagePermissions.ktbackend/data/src/main/kotlin/io/tolgee/dtos/request/project/SetPermissionLanguageParams.ktbackend/data/src/main/kotlin/io/tolgee/facade/ProjectPermissionFacade.ktbackend/data/src/main/kotlin/io/tolgee/model/Permission.ktbackend/data/src/main/kotlin/io/tolgee/model/enums/ProjectPermissionType.ktbackend/data/src/main/kotlin/io/tolgee/model/enums/Scope.ktbackend/data/src/main/kotlin/io/tolgee/repository/PermissionRepository.ktbackend/data/src/main/kotlin/io/tolgee/repository/ProjectRepository.ktbackend/data/src/main/kotlin/io/tolgee/service/CachedPermissionService.ktbackend/data/src/main/kotlin/io/tolgee/service/project/ProjectService.ktbackend/data/src/main/kotlin/io/tolgee/service/security/LanguageDeletedPermissionUpdater.ktbackend/data/src/main/kotlin/io/tolgee/service/security/PermissionService.ktbackend/data/src/main/kotlin/io/tolgee/service/security/SecurityService.ktbackend/data/src/main/resources/db/changelog/schema.xmlbackend/data/src/test/kotlin/io/tolgee/unit/CommunityPermissionScopesTest.ktbackend/data/src/test/kotlin/io/tolgee/unit/MemberInfoMaskingTest.ktbackend/data/src/test/kotlin/io/tolgee/unit/PermissionOrgBaseLanguageGuardTest.ktbackend/development/src/main/kotlin/io/tolgee/controllers/internal/e2eData/ProjectListDashboardE2eDataController.ktbackend/development/src/main/kotlin/io/tolgee/controllers/internal/e2eData/PublicProjectsE2eDataController.kte2e/cypress/common/apiCalls/testData/testData.tse2e/cypress/e2e/administration/base.cy.tse2e/cypress/e2e/projects/communityProjectsNavigation.cy.tse2e/cypress/e2e/projects/projectsListDashboard.cy.tse2e/cypress/e2e/projects/publicProjects.cy.tse2e/cypress/e2e/projects/suggestions/suggestions.reviewer.cy.tse2e/cypress/e2e/projects/suggestions/suggestions.translator.cy.tse2e/cypress/e2e/projects/suggestions/suggestions.unprotected.cy.tse2e/cypress/e2e/translations/translationFilters.suggestions.cy.tse2e/cypress/support/dataCyType.d.tsee/backend/app/src/main/kotlin/io/tolgee/ee/api/v2/controllers/SuggestionController.ktee/backend/app/src/main/kotlin/io/tolgee/ee/api/v2/controllers/TaskController.ktee/backend/app/src/main/kotlin/io/tolgee/ee/api/v2/controllers/branching/BranchController.ktee/backend/app/src/main/kotlin/io/tolgee/ee/repository/TranslationSuggestionRepository.ktee/backend/app/src/main/kotlin/io/tolgee/ee/service/TranslationSuggestionServiceEeImpl.ktee/backend/tests/src/test/kotlin/io/tolgee/ee/api/v2/controllers/AdvancedPermissionControllerTest.ktee/backend/tests/src/test/kotlin/io/tolgee/ee/api/v2/controllers/CommunitySuggestionTest.ktee/backend/tests/src/test/kotlin/io/tolgee/ee/api/v2/controllers/SuggestionControllerTest.ktee/backend/tests/src/test/kotlin/io/tolgee/ee/api/v2/controllers/task/TaskControllerPermissionsTest.ktee/backend/tests/src/test/kotlin/io/tolgee/ee/api/v2/controllers/task/TaskControllerTest.ktwebapp/src/component/PermissionsSettings/LanguagePermissionsSummary.tsxwebapp/src/component/PermissionsSettings/PermissionsSettings.tsxwebapp/src/component/PermissionsSettings/hierarchyTools.tswebapp/src/component/PermissionsSettings/usePermissionsStructure.tswebapp/src/component/PermissionsSettings/useScopeTranslations.tsxwebapp/src/component/RootRouter.tsxwebapp/src/component/SwitchPopover/SwitchPopover.tsxwebapp/src/component/layout/BaseView.tsxwebapp/src/component/layout/HeaderBar.tsxwebapp/src/component/organizationSwitch/CommunityTranslationItem.tsxwebapp/src/component/organizationSwitch/OrganizationPopover.tsxwebapp/src/component/organizationSwitch/OrganizationSwitch.tsxwebapp/src/constants/links.tsxwebapp/src/fixtures/permissions.tswebapp/src/service/apiSchema.generated.tswebapp/src/views/projects/CommunityProjectsView.tsxwebapp/src/views/projects/DashboardProjectListItem.tsxwebapp/src/views/projects/ProjectListView.tsxwebapp/src/views/projects/ProjectsList.tsxwebapp/src/views/projects/dashboard/ProjectTotals.tsxwebapp/src/views/projects/public/CommunityTranslationBanner.tsxwebapp/src/views/projects/public/PublicProjectListView.tsxwebapp/src/views/projects/public/PublicTopBar.tsxwebapp/src/views/projects/public/publicProjectsLayout.tswebapp/src/views/projects/translations/Suggestions/SuggestionsFirst.tsxwebapp/src/views/projects/translations/Suggestions/SuggestionsList.tsxwebapp/src/views/projects/translations/Suggestions/TranslationSuggestion.tsxwebapp/src/views/projects/translations/Suggestions/__tests__/utils.test.tswebapp/src/views/projects/translations/Suggestions/useInfiniteSuggestions.tswebapp/src/views/projects/translations/Suggestions/utils.tswebapp/src/views/projects/translations/TranslationsList/TranslationRead.tsxwebapp/src/views/projects/translations/TranslationsTable/TranslationRead.tsxwebapp/src/views/projects/translations/context/services/useEditService.tsxwebapp/src/views/projects/useLatchedSearchVisibility.tswebapp/src/views/projects/usePublicProjectsList.ts
✅ Files skipped from review due to trivial changes (7)
- webapp/src/views/projects/public/publicProjectsLayout.ts
- backend/api/src/main/kotlin/io/tolgee/hateoas/permission/PermissionWithAgencyModelAssembler.kt
- backend/app/src/main/kotlin/io/tolgee/configuration/WebSecurityConfig.kt
- backend/api/src/main/kotlin/io/tolgee/hateoas/translations/suggestions/TranslationSuggestionSimpleModelAssembler.kt
- backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/translations/v2TranslationsController/TranslationsControllerFilterTest.kt
- backend/api/src/main/kotlin/io/tolgee/hateoas/userAccount/UserAccountInProjectModelAssembler.kt
- e2e/cypress/support/dataCyType.d.ts
🚧 Files skipped from review as they are similar to previous changes (108)
- backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/ProjectsListDashboardTestData.kt
- backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/notification/NotificationControllerTest.kt
- e2e/cypress/e2e/projects/projectsListDashboard.cy.ts
- backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/PublicProjectsStatsTestData.kt
- webapp/src/component/layout/BaseView.tsx
- backend/api/src/main/kotlin/io/tolgee/hateoas/permission/PermissionModelAssembler.kt
- backend/api/src/main/kotlin/io/tolgee/hateoas/project/ProjectWithStatsModelAssembler.kt
- backend/api/src/main/kotlin/io/tolgee/hateoas/permission/IPermissionModel.kt
- backend/api/src/main/kotlin/io/tolgee/hateoas/permission/PermissionModel.kt
- backend/api/src/main/kotlin/io/tolgee/api/v2/controllers/machineTranslation/MtCreditsController.kt
- backend/api/src/main/kotlin/io/tolgee/api/v2/controllers/project/ProjectsPublishingController.kt
- webapp/src/views/projects/translations/Suggestions/useInfiniteSuggestions.ts
- webapp/src/views/projects/translations/TranslationsList/TranslationRead.tsx
- backend/data/src/test/kotlin/io/tolgee/unit/PermissionOrgBaseLanguageGuardTest.kt
- backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/PublicProjectsControllerTestData.kt
- e2e/cypress/e2e/projects/suggestions/suggestions.unprotected.cy.ts
- webapp/src/component/PermissionsSettings/LanguagePermissionsSummary.tsx
- backend/data/src/main/kotlin/io/tolgee/dtos/request/project/SetPermissionLanguageParams.kt
- e2e/cypress/e2e/administration/base.cy.ts
- backend/api/src/main/kotlin/io/tolgee/hateoas/project/ProjectModelAssembler.kt
- backend/data/src/main/kotlin/io/tolgee/repository/PermissionRepository.kt
- backend/data/src/main/kotlin/io/tolgee/dtos/request/project/LanguagePermissions.kt
- backend/api/src/main/kotlin/io/tolgee/hateoas/key/trash/TrashedKeyWithTranslationsModelAssembler.kt
- backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/organizationController/OrganizationProjectsControllerTest.kt
- backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/ProjectPublishingTestData.kt
- webapp/src/views/projects/translations/TranslationsTable/TranslationRead.tsx
- backend/api/src/main/kotlin/io/tolgee/hateoas/apiKey/ApiKeyPermissionsModel.kt
- webapp/src/views/projects/useLatchedSearchVisibility.ts
- backend/data/src/main/kotlin/io/tolgee/model/enums/Scope.kt
- webapp/src/views/projects/translations/context/services/useEditService.tsx
- backend/data/src/main/kotlin/io/tolgee/service/CachedPermissionService.kt
- backend/data/src/main/kotlin/io/tolgee/dtos/queryResults/organization/BasePermissionView.kt
- backend/api/src/main/kotlin/io/tolgee/hateoas/translations/TranslationHistoryModelAssembler.kt
- webapp/src/component/PermissionsSettings/hierarchyTools.ts
- backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/ProjectsTestData.kt
- backend/api/src/main/kotlin/io/tolgee/hateoas/permission/PermissionWithAgencyModel.kt
- backend/data/src/main/kotlin/io/tolgee/constants/ComputedPermissionOrigin.kt
- backend/api/src/main/kotlin/io/tolgee/api/v2/controllers/ApiKeyController.kt
- webapp/src/views/projects/public/PublicTopBar.tsx
- webapp/src/fixtures/permissions.ts
- webapp/src/component/organizationSwitch/CommunityTranslationItem.tsx
- e2e/cypress/common/apiCalls/testData/testData.ts
- backend/development/src/main/kotlin/io/tolgee/controllers/internal/e2eData/PublicProjectsE2eDataController.kt
- backend/data/src/main/kotlin/io/tolgee/dtos/cacheable/PermissionDto.kt
- backend/data/src/main/kotlin/io/tolgee/facade/ProjectPermissionFacade.kt
- backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/ProjectStatsControllerTest.kt
- backend/data/src/main/kotlin/io/tolgee/dtos/cacheable/IPermission.kt
- backend/data/src/test/kotlin/io/tolgee/unit/MemberInfoMaskingTest.kt
- backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/PublicProjectsE2eData.kt
- backend/data/src/main/kotlin/io/tolgee/dtos/request/project/ProjectInviteUserDto.kt
- backend/api/src/main/kotlin/io/tolgee/websocket/ActivityWebsocketListener.kt
- backend/api/src/main/kotlin/io/tolgee/api/v2/controllers/ProjectStatsController.kt
- webapp/src/component/organizationSwitch/OrganizationPopover.tsx
- backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/CommunityPermissionComputationTest.kt
- backend/api/src/main/kotlin/io/tolgee/hateoas/project/ProjectWithStatsModel.kt
- backend/api/src/main/kotlin/io/tolgee/hateoas/userAccount/SimpleUserAccountModelAssembler.kt
- webapp/src/constants/links.tsx
- webapp/src/component/PermissionsSettings/PermissionsSettings.tsx
- webapp/src/views/projects/public/CommunityTranslationBanner.tsx
- webapp/src/component/PermissionsSettings/usePermissionsStructure.ts
- ee/backend/tests/src/test/kotlin/io/tolgee/ee/api/v2/controllers/task/TaskControllerTest.kt
- webapp/src/views/projects/translations/Suggestions/SuggestionsFirst.tsx
- ee/backend/tests/src/test/kotlin/io/tolgee/ee/api/v2/controllers/task/TaskControllerPermissionsTest.kt
- backend/app/src/test/kotlin/io/tolgee/websocket/AbstractWebsocketTest.kt
- ee/backend/app/src/main/kotlin/io/tolgee/ee/api/v2/controllers/branching/BranchController.kt
- backend/data/src/main/kotlin/io/tolgee/model/Permission.kt
- backend/data/src/main/kotlin/io/tolgee/model/enums/ProjectPermissionType.kt
- backend/development/src/main/kotlin/io/tolgee/controllers/internal/e2eData/ProjectListDashboardE2eDataController.kt
- backend/data/src/main/kotlin/io/tolgee/service/security/LanguageDeletedPermissionUpdater.kt
- webapp/src/component/layout/HeaderBar.tsx
- webapp/src/component/SwitchPopover/SwitchPopover.tsx
- backend/app/src/test/kotlin/io/tolgee/service/LanguageDeletePermissionTest.kt
- webapp/src/views/projects/dashboard/ProjectTotals.tsx
- ee/backend/tests/src/test/kotlin/io/tolgee/ee/api/v2/controllers/CommunitySuggestionTest.kt
- webapp/src/views/projects/ProjectListView.tsx
- webapp/src/component/RootRouter.tsx
- ee/backend/app/src/main/kotlin/io/tolgee/ee/repository/TranslationSuggestionRepository.kt
- backend/api/src/main/kotlin/io/tolgee/api/v2/controllers/dataImport/ImportSettingsController.kt
- backend/data/src/main/kotlin/io/tolgee/service/project/ProjectService.kt
- ee/backend/app/src/main/kotlin/io/tolgee/ee/api/v2/controllers/TaskController.kt
- webapp/src/views/projects/translations/Suggestions/SuggestionsList.tsx
- webapp/src/component/PermissionsSettings/useScopeTranslations.tsx
- e2e/cypress/e2e/projects/communityProjectsNavigation.cy.ts
- webapp/src/views/projects/DashboardProjectListItem.tsx
- backend/data/src/main/kotlin/io/tolgee/dtos/request/project/RequestWithLanguagePermissions.kt
- webapp/src/component/organizationSwitch/OrganizationSwitch.tsx
- backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/LanguagePermissionsTestData.kt
- webapp/src/views/projects/ProjectsList.tsx
- ee/backend/tests/src/test/kotlin/io/tolgee/ee/api/v2/controllers/SuggestionControllerTest.kt
- backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/SuggestionsTestData.kt
- ee/backend/tests/src/test/kotlin/io/tolgee/ee/api/v2/controllers/AdvancedPermissionControllerTest.kt
- ee/backend/app/src/main/kotlin/io/tolgee/ee/service/TranslationSuggestionServiceEeImpl.kt
- backend/api/src/main/kotlin/io/tolgee/hateoas/activity/ProjectActivityModelAssembler.kt
- backend/data/src/main/kotlin/io/tolgee/service/security/PermissionService.kt
- backend/data/src/main/kotlin/io/tolgee/repository/ProjectRepository.kt
- e2e/cypress/e2e/projects/publicProjects.cy.ts
- e2e/cypress/e2e/projects/suggestions/suggestions.translator.cy.ts
- e2e/cypress/e2e/translations/translationFilters.suggestions.cy.ts
- e2e/cypress/e2e/projects/suggestions/suggestions.reviewer.cy.ts
- backend/data/src/main/kotlin/io/tolgee/service/security/SecurityService.kt
- webapp/src/views/projects/translations/Suggestions/TranslationSuggestion.tsx
- backend/api/src/main/kotlin/io/tolgee/hateoas/key/trash/TrashedKeyModelAssembler.kt
- backend/data/src/main/kotlin/io/tolgee/dtos/ComputedPermissionDto.kt
- backend/data/src/test/kotlin/io/tolgee/unit/CommunityPermissionScopesTest.kt
- backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/CommunityPermissionTest.kt
- backend/data/src/main/resources/db/changelog/schema.xml
- webapp/src/service/apiSchema.generated.ts
- backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/PublicProjectsControllerTest.kt
5d8a325 to
43c0984
Compare
| const value = !project.public; | ||
| confirmation({ | ||
| title: value ? ( | ||
| <T keyName="project_settings_make_public_dialog_title" /> |
There was a problem hiding this comment.
I believe we all started to use a defaultValue for all new translation keys. Do you intentionally miss them? Tbh, I’m fine with both options, as long as you don't forget to add translations.
There was a problem hiding this comment.
Yee, it is intentional ^^
We need to sit down to discuss this. I think it's a bad idea because it masks problems. When a translation is missing, we won't notice because the default value is used. Plus, the default value could become outdated since no one will update it when the translation changes in Tolgee UI/in-context.
I plan to remove the rule in PR #3574, but I haven't finished it yet. The main difference would be that the agent adds the default value only temporarily.
I used to tell myself that at least we have the test checking for missing translations, so the default values can't break anything. Then I found out the test had been broken for half a year (#3787) and nobody had noticed. :D
Either way, I can add them if we decide to go that route, but yes, it's intentional. ^^
|
Good job @Anty0. I haven't found anything critical. |
Add a `public` flag to projects, flippable only by the organization
owner (or a server admin) via a dedicated endpoint
(PUT /v2/projects/{id}/publishing). Surfaced as a confirmation-guarded
switch in advanced project settings.
First sub-task of Community Translation v1.0 (#3763). The public-projects
discovery page, community permission, and the public/private indicator
(pending design) follow as separate sub-tasks merged into this branch.
Authenticated users on a public project get a computed community permission (read subset of VIEW + translations-suggest + translation-comments-add, all languages; origin COMMUNITY) without a stored Permission row — they contribute translations without taking a paid seat. Direct/org permissions and admin/supporter elevation layer on top, so no authenticated user is below a non-member; anonymous users get nothing. - Member emails and the project member count are redacted behind MEMBERS_VIEW across project-scoped REST surfaces; the realtime websocket never carries the author email. - Out-of-surface endpoints reachable by the community scope set are gated: MT credit balance -> ORGANIZATION_QUOTAS_VIEW, import-settings store -> KEYS_CREATE, branch-merge sessions -> BRANCH_MANAGEMENT, blocking-tasks -> task-view-or-assigned. BREAKING CHANGE: GET project machine-translation-credit-balance now requires ORGANIZATION_QUOTAS_VIEW; granular permissions and API keys without it get 403 and must be re-granted. Branch-merge session endpoints now require BRANCH_MANAGEMENT.
Part of the Community Translation v1.0 pitch (#3763), PR 1 — Public projects. Targets the `jirikuchynka/public-projects` branch. ## What Public projects now show a **second line** under the project name in the project list row: an outlined lowercase **`public`** badge followed by the **organization name**. Per the shaped pitch, this list-row badge is the *only* public indicator — there is no separate icon in the project detail view. ## Changes - **Backend**: add `public: Boolean` to `ProjectWithStatsModel` + map it in `ProjectWithStatsModelAssembler`; regenerate the frontend API schema. - **Frontend**: `DashboardProjectListItem` renders the badge (`TransparentChip`, i18n key `project_list_public_badge`) + organization name when the project is public. - **Tests**: backend `OrganizationProjectsControllerTest` asserts the `public` flag is serialized (public + private); cypress `projectsListDashboard.cy.ts` asserts the badge + org name render on a public row and are absent on a private row. ## Verification - Backend test green; ktlint green. - webapp + e2e eslint + tsc green. - Cypress `projectsListDashboard.cy.ts` — all 5 tests pass (incl. the 2 new badge tests) against a live dev stack. ## Notes - i18n key `project_list_public_badge` ("public") created in the Tolgee project; no inline default in code (matches sibling keys). - In the normal org list the title column is 150px, so very long org names ellipsize (consistent with the existing project-name layout). Full names show in the wider community/public list layouts (later PRs in this pitch).
…ine others" (#3776) Part of the Community Translation v1.0 pitch (suggestion resolution split). Stacked on top of `jirikuchynka/public-projects` — merge that first. ## What Splits the single suggestion **Accept** action into two: - **Accept only** — accepts this suggestion and leaves the competing suggestions active (`declineOther=false`). - **Accept and decline others** — accepts this one and declines the rest (`declineOther=true`, the previous behavior). ### UI (decided with design) - Inline row actions: **✓ Accept only** and **✕ Decline** (inactive rows show **↺ Reactivate**). - Overflow **⋮** menu holds the secondary actions: **Accept and decline others** and **Delete** (the latter only on your own suggestion). The menu only renders when at least one of those applies. ## Scope Frontend-only — the backend already supported `declineOther` on the accept endpoint (`SuggestionController.acceptSuggestion`), so no backend, migration, or API-schema changes. ## Notable details - Optimistic cache fix in `applyAcceptedSuggestion`: on accept-only it decrements `activeSuggestionCount` but leaves the single-item preview for the `invalidatePrefix` refetch to reconcile — so the surviving sibling stays visible and no stale count / phantom `+N` chip flashes. Covered by a vitest unit test. - `accept-and-decline-others` is gated on the row being **active** (so it never appears on declined rows in show-all view). ## i18n Two new keys created in the **Tolgee itself** project via the Tolgee API (tagged `draft: suggestion-resolution-split`): `translation_suggestion_accept_only`, `translation_suggestion_accept_and_decline_others`. The previously-unused `translation_suggestion_show_more_tooltip` is referenced again by the kebab. ## Tests - Vitest: `applyAcceptedSuggestion` (6 cases). - Cypress: reworked the suggestion specs for the inline/kebab split (accept-only keeps the sibling, accept-and-decline-others clears it, kebab delete, single-suggestion has no kebab, translator can't accept). ### Known follow-ups - The `active &&` guard's show-all false-branch is not e2e-covered (a 3-active fixture would break the backend `filters by suggestion` test and key-0 count assertions; the cheap route later is a pure action-builder helper unit-tested in vitest). - In-flight `disabled` on menu items not e2e-asserted (flaky to test deterministically).
93e6fd9 to
1db65f9
Compare
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
webapp/src/component/organizationSwitch/OrganizationPopover.tsx (1)
5-5: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueUse
tg.componentfor both new component imports. These sibling-relative imports bypass the repository’s required TypeScript alias convention.
webapp/src/component/organizationSwitch/OrganizationPopover.tsx#L5-L5: importCommunityTranslationItemthroughtg.component.webapp/src/component/organizationSwitch/OrganizationSwitch.tsx#L7-L7: importCommunityTranslationItemthroughtg.component.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@webapp/src/component/organizationSwitch/OrganizationPopover.tsx` at line 5, Replace the relative CommunityTranslationItem imports with the repository-standard tg.component alias in both OrganizationPopover.tsx (line 5) and OrganizationSwitch.tsx (line 7).Source: Coding guidelines
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@webapp/src/component/organizationSwitch/OrganizationSwitch.tsx`:
- Around line 81-90: Update OrganizationSwitch to accept an onCommunityNavigate
callback and forward it to OrganizationPopover alongside the existing
communitySelected prop, preserving the current organization selection and
navigation behavior.
In `@webapp/src/component/PermissionsSettings/useScopeTranslations.tsx`:
- Around line 12-14: Add meaningful defaultValue fallbacks to both new
translation calls in useScopeTranslations:
permissions_item_translations_suggestions_manage at
webapp/src/component/PermissionsSettings/useScopeTranslations.tsx lines 12-14
and permissions_item_organization_quotas_view at line 59. Keep the existing
translation keys and use fallback text matching each permission label.
---
Nitpick comments:
In `@webapp/src/component/organizationSwitch/OrganizationPopover.tsx`:
- Line 5: Replace the relative CommunityTranslationItem imports with the
repository-standard tg.component alias in both OrganizationPopover.tsx (line 5)
and OrganizationSwitch.tsx (line 7).
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 958286d2-2665-484e-893c-b371a5f14621
⛔ Files ignored due to path filters (1)
webapp/public/images/communityMouse.svgis excluded by!**/*.svg
📒 Files selected for processing (110)
backend/api/src/main/kotlin/io/tolgee/api/v2/controllers/ApiKeyController.ktbackend/api/src/main/kotlin/io/tolgee/api/v2/controllers/ProjectStatsController.ktbackend/api/src/main/kotlin/io/tolgee/api/v2/controllers/dataImport/ImportSettingsController.ktbackend/api/src/main/kotlin/io/tolgee/api/v2/controllers/machineTranslation/MtCreditsController.ktbackend/api/src/main/kotlin/io/tolgee/api/v2/controllers/project/ProjectsPublishingController.ktbackend/api/src/main/kotlin/io/tolgee/api/v2/controllers/project/PublicProjectsController.ktbackend/api/src/main/kotlin/io/tolgee/hateoas/activity/ProjectActivityModelAssembler.ktbackend/api/src/main/kotlin/io/tolgee/hateoas/apiKey/ApiKeyPermissionsModel.ktbackend/api/src/main/kotlin/io/tolgee/hateoas/key/trash/TrashedKeyModelAssembler.ktbackend/api/src/main/kotlin/io/tolgee/hateoas/key/trash/TrashedKeyWithTranslationsModelAssembler.ktbackend/api/src/main/kotlin/io/tolgee/hateoas/permission/IPermissionModel.ktbackend/api/src/main/kotlin/io/tolgee/hateoas/permission/PermissionModel.ktbackend/api/src/main/kotlin/io/tolgee/hateoas/permission/PermissionModelAssembler.ktbackend/api/src/main/kotlin/io/tolgee/hateoas/permission/PermissionWithAgencyModel.ktbackend/api/src/main/kotlin/io/tolgee/hateoas/permission/PermissionWithAgencyModelAssembler.ktbackend/api/src/main/kotlin/io/tolgee/hateoas/project/ProjectModel.ktbackend/api/src/main/kotlin/io/tolgee/hateoas/project/ProjectModelAssembler.ktbackend/api/src/main/kotlin/io/tolgee/hateoas/project/ProjectWithStatsModel.ktbackend/api/src/main/kotlin/io/tolgee/hateoas/project/ProjectWithStatsModelAssembler.ktbackend/api/src/main/kotlin/io/tolgee/hateoas/translations/TranslationHistoryModelAssembler.ktbackend/api/src/main/kotlin/io/tolgee/hateoas/translations/suggestions/TranslationSuggestionSimpleModelAssembler.ktbackend/api/src/main/kotlin/io/tolgee/hateoas/userAccount/SimpleUserAccountModelAssembler.ktbackend/api/src/main/kotlin/io/tolgee/hateoas/userAccount/UserAccountInProjectModelAssembler.ktbackend/api/src/main/kotlin/io/tolgee/websocket/ActivityWebsocketListener.ktbackend/app/src/main/kotlin/io/tolgee/configuration/WebSecurityConfig.ktbackend/app/src/test/kotlin/io/tolgee/api/v2/controllers/CommunityPermissionComputationTest.ktbackend/app/src/test/kotlin/io/tolgee/api/v2/controllers/CommunityPermissionTest.ktbackend/app/src/test/kotlin/io/tolgee/api/v2/controllers/ProjectStatsControllerTest.ktbackend/app/src/test/kotlin/io/tolgee/api/v2/controllers/PublicProjectsControllerTest.ktbackend/app/src/test/kotlin/io/tolgee/api/v2/controllers/notification/NotificationControllerTest.ktbackend/app/src/test/kotlin/io/tolgee/api/v2/controllers/organizationController/OrganizationProjectsControllerTest.ktbackend/app/src/test/kotlin/io/tolgee/api/v2/controllers/translations/v2TranslationsController/TranslationsControllerFilterTest.ktbackend/app/src/test/kotlin/io/tolgee/api/v2/controllers/v2ProjectsController/ProjectsControllerPublishingTest.ktbackend/app/src/test/kotlin/io/tolgee/service/LanguageDeletePermissionTest.ktbackend/app/src/test/kotlin/io/tolgee/service/ProjectPublishingCachingTest.ktbackend/app/src/test/kotlin/io/tolgee/websocket/AbstractWebsocketTest.ktbackend/data/src/main/kotlin/io/tolgee/constants/ComputedPermissionOrigin.ktbackend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/LanguagePermissionsTestData.ktbackend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/ProjectPublishingTestData.ktbackend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/ProjectsListDashboardTestData.ktbackend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/ProjectsTestData.ktbackend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/PublicProjectsControllerTestData.ktbackend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/PublicProjectsE2eData.ktbackend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/PublicProjectsStatsTestData.ktbackend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/SuggestionsTestData.ktbackend/data/src/main/kotlin/io/tolgee/dtos/ComputedPermissionDto.ktbackend/data/src/main/kotlin/io/tolgee/dtos/cacheable/IPermission.ktbackend/data/src/main/kotlin/io/tolgee/dtos/cacheable/PermissionDto.ktbackend/data/src/main/kotlin/io/tolgee/dtos/cacheable/ProjectDto.ktbackend/data/src/main/kotlin/io/tolgee/dtos/queryResults/organization/BasePermissionView.ktbackend/data/src/main/kotlin/io/tolgee/dtos/request/project/LanguagePermissions.ktbackend/data/src/main/kotlin/io/tolgee/dtos/request/project/ProjectInviteUserDto.ktbackend/data/src/main/kotlin/io/tolgee/dtos/request/project/RequestWithLanguagePermissions.ktbackend/data/src/main/kotlin/io/tolgee/dtos/request/project/SetPermissionLanguageParams.ktbackend/data/src/main/kotlin/io/tolgee/dtos/request/project/SetProjectPublicRequest.ktbackend/data/src/main/kotlin/io/tolgee/facade/ProjectPermissionFacade.ktbackend/data/src/main/kotlin/io/tolgee/model/Permission.ktbackend/data/src/main/kotlin/io/tolgee/model/Project.ktbackend/data/src/main/kotlin/io/tolgee/model/enums/ProjectPermissionType.ktbackend/data/src/main/kotlin/io/tolgee/model/enums/Scope.ktbackend/data/src/main/kotlin/io/tolgee/model/views/ProjectView.ktbackend/data/src/main/kotlin/io/tolgee/model/views/ProjectWithLanguagesView.ktbackend/data/src/main/kotlin/io/tolgee/model/views/ProjectWithStatsView.ktbackend/data/src/main/kotlin/io/tolgee/repository/PermissionRepository.ktbackend/data/src/main/kotlin/io/tolgee/repository/ProjectRepository.ktbackend/data/src/main/kotlin/io/tolgee/service/CachedPermissionService.ktbackend/data/src/main/kotlin/io/tolgee/service/project/ProjectService.ktbackend/data/src/main/kotlin/io/tolgee/service/security/LanguageDeletedPermissionUpdater.ktbackend/data/src/main/kotlin/io/tolgee/service/security/PermissionService.ktbackend/data/src/main/kotlin/io/tolgee/service/security/SecurityService.ktbackend/data/src/main/resources/db/changelog/schema.xmlbackend/data/src/test/kotlin/io/tolgee/unit/CommunityPermissionScopesTest.ktbackend/data/src/test/kotlin/io/tolgee/unit/MemberInfoMaskingTest.ktbackend/data/src/test/kotlin/io/tolgee/unit/PermissionOrgBaseLanguageGuardTest.ktbackend/development/src/main/kotlin/io/tolgee/controllers/internal/e2eData/ProjectListDashboardE2eDataController.ktbackend/development/src/main/kotlin/io/tolgee/controllers/internal/e2eData/PublicProjectsE2eDataController.kte2e/cypress/common/apiCalls/testData/testData.tse2e/cypress/common/shared.tse2e/cypress/e2e/administration/base.cy.tse2e/cypress/e2e/projects/communityProjectsNavigation.cy.tse2e/cypress/e2e/projects/projectsListDashboard.cy.tse2e/cypress/e2e/projects/publicProjects.cy.tse2e/cypress/e2e/projects/settings.public.cy.tse2e/cypress/e2e/projects/suggestions/suggestions.reviewer.cy.tse2e/cypress/e2e/projects/suggestions/suggestions.translator.cy.tse2e/cypress/e2e/projects/suggestions/suggestions.unprotected.cy.tse2e/cypress/e2e/translations/translationFilters.suggestions.cy.tse2e/cypress/support/dataCyType.d.tsee/backend/app/src/main/kotlin/io/tolgee/ee/api/v2/controllers/SuggestionController.ktee/backend/app/src/main/kotlin/io/tolgee/ee/api/v2/controllers/TaskController.ktee/backend/app/src/main/kotlin/io/tolgee/ee/api/v2/controllers/branching/BranchController.ktee/backend/app/src/main/kotlin/io/tolgee/ee/repository/TranslationSuggestionRepository.ktee/backend/app/src/main/kotlin/io/tolgee/ee/service/TranslationSuggestionServiceEeImpl.ktee/backend/tests/src/test/kotlin/io/tolgee/ee/api/v2/controllers/AdvancedPermissionControllerTest.ktee/backend/tests/src/test/kotlin/io/tolgee/ee/api/v2/controllers/CommunitySuggestionTest.ktee/backend/tests/src/test/kotlin/io/tolgee/ee/api/v2/controllers/SuggestionControllerTest.ktee/backend/tests/src/test/kotlin/io/tolgee/ee/api/v2/controllers/task/TaskControllerPermissionsTest.ktee/backend/tests/src/test/kotlin/io/tolgee/ee/api/v2/controllers/task/TaskControllerTest.ktwebapp/src/component/PermissionsSettings/LanguagePermissionsSummary.tsxwebapp/src/component/PermissionsSettings/PermissionsSettings.tsxwebapp/src/component/PermissionsSettings/hierarchyTools.tswebapp/src/component/PermissionsSettings/usePermissionsStructure.tswebapp/src/component/PermissionsSettings/useScopeTranslations.tsxwebapp/src/component/RootRouter.tsxwebapp/src/component/SwitchPopover/SwitchPopover.tsxwebapp/src/component/layout/BaseView.tsxwebapp/src/component/layout/HeaderBar.tsxwebapp/src/component/organizationSwitch/CommunityTranslationItem.tsxwebapp/src/component/organizationSwitch/OrganizationPopover.tsxwebapp/src/component/organizationSwitch/OrganizationSwitch.tsx
🚧 Files skipped from review as they are similar to previous changes (94)
- backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/ProjectsListDashboardTestData.kt
- backend/data/src/test/kotlin/io/tolgee/unit/MemberInfoMaskingTest.kt
- backend/data/src/main/kotlin/io/tolgee/dtos/request/project/SetProjectPublicRequest.kt
- backend/data/src/main/kotlin/io/tolgee/dtos/cacheable/IPermission.kt
- e2e/cypress/e2e/projects/suggestions/suggestions.unprotected.cy.ts
- backend/app/src/main/kotlin/io/tolgee/configuration/WebSecurityConfig.kt
- backend/data/src/main/kotlin/io/tolgee/dtos/cacheable/ProjectDto.kt
- backend/api/src/main/kotlin/io/tolgee/hateoas/userAccount/UserAccountInProjectModelAssembler.kt
- backend/api/src/main/kotlin/io/tolgee/hateoas/apiKey/ApiKeyPermissionsModel.kt
- backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/ProjectsTestData.kt
- backend/data/src/main/kotlin/io/tolgee/model/views/ProjectView.kt
- backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/translations/v2TranslationsController/TranslationsControllerFilterTest.kt
- backend/api/src/main/kotlin/io/tolgee/hateoas/permission/PermissionModel.kt
- backend/data/src/main/kotlin/io/tolgee/dtos/request/project/RequestWithLanguagePermissions.kt
- backend/data/src/main/kotlin/io/tolgee/dtos/request/project/SetPermissionLanguageParams.kt
- webapp/src/component/organizationSwitch/CommunityTranslationItem.tsx
- e2e/cypress/e2e/administration/base.cy.ts
- webapp/src/component/PermissionsSettings/hierarchyTools.ts
- backend/data/src/main/kotlin/io/tolgee/model/views/ProjectWithStatsView.kt
- backend/data/src/main/kotlin/io/tolgee/model/Project.kt
- backend/api/src/main/kotlin/io/tolgee/hateoas/permission/PermissionWithAgencyModel.kt
- backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/PublicProjectsStatsTestData.kt
- backend/data/src/test/kotlin/io/tolgee/unit/PermissionOrgBaseLanguageGuardTest.kt
- backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/organizationController/OrganizationProjectsControllerTest.kt
- backend/api/src/main/kotlin/io/tolgee/hateoas/key/trash/TrashedKeyModelAssembler.kt
- backend/api/src/main/kotlin/io/tolgee/api/v2/controllers/ProjectStatsController.kt
- webapp/src/component/PermissionsSettings/PermissionsSettings.tsx
- backend/development/src/main/kotlin/io/tolgee/controllers/internal/e2eData/PublicProjectsE2eDataController.kt
- backend/api/src/main/kotlin/io/tolgee/hateoas/translations/TranslationHistoryModelAssembler.kt
- backend/api/src/main/kotlin/io/tolgee/hateoas/project/ProjectModel.kt
- backend/api/src/main/kotlin/io/tolgee/hateoas/project/ProjectWithStatsModel.kt
- ee/backend/tests/src/test/kotlin/io/tolgee/ee/api/v2/controllers/task/TaskControllerPermissionsTest.kt
- backend/api/src/main/kotlin/io/tolgee/hateoas/key/trash/TrashedKeyWithTranslationsModelAssembler.kt
- backend/data/src/main/kotlin/io/tolgee/repository/PermissionRepository.kt
- ee/backend/app/src/main/kotlin/io/tolgee/ee/repository/TranslationSuggestionRepository.kt
- backend/api/src/main/kotlin/io/tolgee/hateoas/permission/IPermissionModel.kt
- backend/data/src/main/kotlin/io/tolgee/constants/ComputedPermissionOrigin.kt
- backend/api/src/main/kotlin/io/tolgee/hateoas/project/ProjectWithStatsModelAssembler.kt
- e2e/cypress/e2e/translations/translationFilters.suggestions.cy.ts
- backend/api/src/main/kotlin/io/tolgee/hateoas/permission/PermissionWithAgencyModelAssembler.kt
- backend/data/src/main/kotlin/io/tolgee/model/views/ProjectWithLanguagesView.kt
- webapp/src/component/PermissionsSettings/LanguagePermissionsSummary.tsx
- backend/api/src/main/kotlin/io/tolgee/api/v2/controllers/ApiKeyController.kt
- backend/api/src/main/kotlin/io/tolgee/hateoas/project/ProjectModelAssembler.kt
- backend/api/src/main/kotlin/io/tolgee/hateoas/activity/ProjectActivityModelAssembler.kt
- backend/data/src/main/kotlin/io/tolgee/repository/ProjectRepository.kt
- backend/api/src/main/kotlin/io/tolgee/websocket/ActivityWebsocketListener.kt
- backend/data/src/main/kotlin/io/tolgee/facade/ProjectPermissionFacade.kt
- backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/PublicProjectsControllerTestData.kt
- backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/notification/NotificationControllerTest.kt
- backend/development/src/main/kotlin/io/tolgee/controllers/internal/e2eData/ProjectListDashboardE2eDataController.kt
- backend/data/src/main/kotlin/io/tolgee/dtos/cacheable/PermissionDto.kt
- backend/data/src/main/kotlin/io/tolgee/dtos/request/project/LanguagePermissions.kt
- webapp/src/component/PermissionsSettings/usePermissionsStructure.ts
- e2e/cypress/e2e/projects/projectsListDashboard.cy.ts
- backend/api/src/main/kotlin/io/tolgee/hateoas/permission/PermissionModelAssembler.kt
- backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/v2ProjectsController/ProjectsControllerPublishingTest.kt
- backend/app/src/test/kotlin/io/tolgee/websocket/AbstractWebsocketTest.kt
- e2e/cypress/e2e/projects/communityProjectsNavigation.cy.ts
- backend/data/src/main/kotlin/io/tolgee/model/Permission.kt
- backend/data/src/main/kotlin/io/tolgee/model/enums/ProjectPermissionType.kt
- ee/backend/app/src/main/kotlin/io/tolgee/ee/api/v2/controllers/TaskController.kt
- backend/data/src/main/kotlin/io/tolgee/service/CachedPermissionService.kt
- backend/app/src/test/kotlin/io/tolgee/service/ProjectPublishingCachingTest.kt
- e2e/cypress/common/apiCalls/testData/testData.ts
- backend/data/src/main/kotlin/io/tolgee/model/enums/Scope.kt
- ee/backend/tests/src/test/kotlin/io/tolgee/ee/api/v2/controllers/AdvancedPermissionControllerTest.kt
- ee/backend/tests/src/test/kotlin/io/tolgee/ee/api/v2/controllers/task/TaskControllerTest.kt
- backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/PublicProjectsE2eData.kt
- e2e/cypress/support/dataCyType.d.ts
- backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/CommunityPermissionComputationTest.kt
- ee/backend/tests/src/test/kotlin/io/tolgee/ee/api/v2/controllers/CommunitySuggestionTest.kt
- backend/app/src/test/kotlin/io/tolgee/api/v2/controllers/PublicProjectsControllerTest.kt
- backend/data/src/main/kotlin/io/tolgee/service/security/PermissionService.kt
- backend/data/src/main/kotlin/io/tolgee/service/security/LanguageDeletedPermissionUpdater.kt
- webapp/src/component/SwitchPopover/SwitchPopover.tsx
- e2e/cypress/e2e/projects/publicProjects.cy.ts
- webapp/src/component/RootRouter.tsx
- backend/data/src/main/kotlin/io/tolgee/dtos/ComputedPermissionDto.kt
- backend/api/src/main/kotlin/io/tolgee/api/v2/controllers/dataImport/ImportSettingsController.kt
- backend/data/src/main/resources/db/changelog/schema.xml
- backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/SuggestionsTestData.kt
- ee/backend/app/src/main/kotlin/io/tolgee/ee/api/v2/controllers/branching/BranchController.kt
- e2e/cypress/e2e/projects/suggestions/suggestions.translator.cy.ts
- e2e/cypress/e2e/projects/suggestions/suggestions.reviewer.cy.ts
- backend/data/src/main/kotlin/io/tolgee/service/security/SecurityService.kt
- backend/data/src/main/kotlin/io/tolgee/service/project/ProjectService.kt
- ee/backend/tests/src/test/kotlin/io/tolgee/ee/api/v2/controllers/SuggestionControllerTest.kt
- e2e/cypress/e2e/projects/settings.public.cy.ts
- backend/data/src/test/kotlin/io/tolgee/unit/CommunityPermissionScopesTest.kt
- ee/backend/app/src/main/kotlin/io/tolgee/ee/service/TranslationSuggestionServiceEeImpl.kt
- backend/data/src/main/kotlin/io/tolgee/dtos/queryResults/organization/BasePermissionView.kt
- backend/app/src/test/kotlin/io/tolgee/service/LanguageDeletePermissionTest.kt
- backend/data/src/main/kotlin/io/tolgee/development/testDataBuilder/data/LanguagePermissionsTestData.kt
## What Part of the Community Translation v1.0 pitch (suggestion behavior changes). The translations list read view showed a single suggestion per cell; it now shows **up to 3** by default, keeping the existing **`+N`** overflow badge as the indicator (no new control). Targets `jirikuchynka/public-projects` to be folded into that PR. ## Changes **Backend** - `TranslationSuggestionRepository.getByKeyId` swaps `DISTINCT ON` (1 row/group) for a `row_number()` windowed top-N (`rn <= :maxPerKey`) with an explicit outer `ORDER BY` — the window `OVER(...)` order only assigns `row_number()`, not the delivery order. Ordering is `created_at desc, id desc`. - `MAX_DISPLAYED_SUGGESTIONS = 3` constant in `TranslationSuggestionServiceEeImpl` drives the cap. - No new index: the `WHERE` predicate is unchanged from the previous query and the existing `(project_id, language_id, key_id)` composite index covers it. **Frontend** - The read view (`SuggestionsFirst`) renders up to 3 and self-caps in render; the `+N` badge is guarded non-negative. - The cell cache stays at 3 across the editor **open/close**, **mutate**, and **suggest-create** paths (the suggest path previously collapsed the stack to 1). - The editor suggestion query gains an `id,desc` sort tiebreaker so its order matches the embed. ## Tests - Backend: embed cap (3) + `activeSuggestionCount`, per-`(key, language)` partition isolation, cap-by-constant, and a dedicated `created_at desc` primary-sort test (created via API at non-id-monotonic timestamps so id-order and createdAt-order disagree). - Cypress: read-cell 3-stack + `+N`, open/close, suggest-keeps-3, decline-then-resync, and a table-view check. Backend test suite green; frontend `eslint`/`tsc` green for `webapp` and `e2e`.
Adds a logged-out-capable /public-projects page listing all public projects (stats, search, paging) via a new anonymous GET /v2/public/projects/with-stats endpoint, reusing the project-list UI with a community-translation onboarding banner. - Backend: PublicProjectsController (anonymous, @OpenApiHideFromPublicDocs, @transactional(readOnly=true)); ProjectService.findAllPublicPaged (NO_USER_ID sentinel); ProjectRepository.findAllPublic (reuses BASE_VIEW_QUERY; guards public/deleted/org-owner/base-language to keep the anonymous read side-effect-free + community-permission floor via #3770). - Frontend: /public-projects route, PublicProjectListView + PublicTopBar + community-translation banner (Figma-matched gradient, dev-mouse mascot, left-anchored gated search); shared ProjectsList extracted from ProjectListView; DashboardProjectListItem variant='public' (member affordances suppressed, row click -> project when logged-in, else login). - Tests: PublicProjectsControllerTest (anonymous/member/community/direct-permission joins, guard filters, case-insensitive search) + publicProjects.cy.ts E2E.
Projects-page redesign lane of Community Translation v1.0 (#3763). - Projects list header: centered "Projects" title with the org switcher relocated next to it (standaloneTitle: hides the separator, adds top spacing, stacks search on its own row). Every non-list page keeps the top-left switcher. - Synthetic "Community translation" switcher entry navigating to /community-projects (does not switch org). Implemented but temporarily disabled pending contributor tracking; its e2e tests are skipped with a re-enable TODO. - /community-projects page: projects-list shell that ignores the selected org and lists all public projects, email-verification gated, with the community-translation banner on top (per designer). - DashboardProjectListItem gains a public grid variant that drops the controls column entirely (no reserved space); default layout title width 150px -> 180px, smaller breakpoints unchanged. - New i18n keys created in "Tolgee itself"; default values stripped.
## What Adds a new permission scope **`translation-suggestions.manage`** that lets project members delete translation suggestions authored by **other users**. Previously a community suggestion could be deleted only by its author, so there was no way for project members to clean up spam / bad suggestions. Part of Community Translation v1.0 (#3763). Targets the `jirikuchynka/public-projects` integration branch. ## Details - **New scope** `translation-suggestions.manage` (enum `TRANSLATION_SUGGESTIONS_MANAGE`), following the `translation-labels.manage` sub-entity naming convention. Granted to the **EDIT** preset (and MANAGE via ADMIN). - **Own per-language dimension** `suggestManageLanguages` (new `@ManyToMany` join table `permission_suggest_manage_languages` + migration with FK constraints), so a moderator can be restricted to specific languages — wired end-to-end incl. the language-deletion cleanup + de-escalation path. - **Granular editor:** `Suggest` and `Manage` are grouped under a new **"Suggestions"** category, each with its own language selector. - **Enforcement:** deleting another user's suggestion is gated on the scope + language (like the sibling suggestion actions); the author fast-path (delete your own) is unchanged. The list endpoint now accepts `suggest` **OR** `manage` so moderators can see the suggestions they can act on. ## Behavior changes to note - **Permission change:** on merge, existing **EDIT/MANAGE** project members gain the ability to delete other users' suggestions. - **Delete-only:** the scope gates deletion only; `decline`/`accept`/`set-active` intentionally remain on `translations.state-edit`. - i18n keys created in the Tolgee project (`permissions_item_translations_suggestions`, `permissions_item_translations_suggestions_manage`, `permission_type_suggest_manage`), tagged `draft: suggestion-moderation`. ## Follow-up / not in this PR - Consolidating the 5 parallel language dimensions into one scope-discriminated table (accepted architecture debt). - Deferred tests: PAK/API-key delete, community-boundary integration, FE Cypress e2e.
e20b538 to
d42feb8
Compare
Re-lands the organization-permissions lane of Community Translation v1,
which is missing from `main`.
## The problem
Opening a public project partially fails. The frontend sets the
preferred organization to the project's owner org on every project open
(`ProjectContext.tsx` → `PUT
/v2/user-preferences/set-preferred-organization/{id}`), and that call is
rejected for community users.
`main` still has the strict check in `UserPreferencesController`:
```kotlin
organizationRoleService.checkUserCanView(organization.id)
```
which resolves to `OrganizationRepository.canUserView`, whose predicate
is `(perm is not null or mr is not null)` — it requires a **stored**
`Permission` or `OrganizationRole` row. The community floor from #3770
is *computed* by design, so contributors don't consume a paid seat. No
row → `PermissionException(USER_CANNOT_VIEW_THIS_ORGANIZATION)` → 403.
## How it went missing
#3792 was merged into `jirikuchynka/public-projects` on 2026-07-13
(merge commit `93e6fd9cc`). That branch was subsequently rebased and
force-pushed; the rebase dropped the merge commit along with its two
payload commits. #3765 then squash-merged the rebased branch into `main`
as `4a4ea3f55`, shipping v1 without this lane. GitHub still reports
#3792 as MERGED, which is why it went unnoticed.
## This PR
`git cherry-pick -m 1 93e6fd9` onto `main` — applied with no
conflicts, and the resulting diff against `main` is identical to the
original payload (55 files, 2197+/129-).
Contents (unchanged from #3792):
- `OrganizationRoleService.canUserViewStrictOrPublic` /
`checkUserCanViewOrPublic` — the org view floor: strict check OR
`projectService.hasPublicProjects(organizationId)`
- Applied at `UserPreferencesController:61` and
`OrganizationAuthorizationInterceptor:75`
- `PreferredOrganizationFacade` heals stale/missing preferences in place
and emits `PrivateOrganizationModel.limitedView` for below-member
viewers
- Scoping of org language reads to accessible projects for below-member
viewers
- Glossary guest access, member-listing and usage exclusions for floor
viewers
## Verification
- `:data:`/`:api:`/`:security:`/`:development:compileKotlin` — BUILD
SUCCESSFUL
- `UserPreferencesSetPreferredOrganizationTest` — 7/7 passed
- `OrganizationFloorAccessTest` — 29/29 passed
- webapp + e2e `eslint --fix` and `tsc` — clean, no files changed
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Community and below-member viewers now receive organization models
tailored to public-project access, including a new `limitedView` flag
and safer subscription-related visibility behavior.
* **Bug Fixes**
* Preferred-organization and “managed-by” responses now respect updated
viewability rules and permission filtering, with stronger
stale-preference healing when the stored organization becomes
unavailable.
* Organization language/project listing queries are now restricted to
only the projects accessible to the current caller.
* Authorization “view floor” enforcement was tightened to allow the
correct default endpoints while keeping role-required routes protected.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
## [3.213.1](v3.213.0...v3.213.1) (2026-07-20) ### Bug Fixes * community access to public-project organizations ([#3808](#3808)) ([6a7f73f](6a7f73f)), closes [#3770](#3770) [#3792](#3792) [#3765](#3765) [#3792](#3792) [#3792](#3792) * keep websocket connection alive when a subscription is denied ([#3809](#3809)) ([1235ad1](1235ad1)), closes [#3529](#3529) [#3621](#3621) [#3621](#3621)
Integration branch for Community Translation v1.0 (#3763). Individual lanes are reviewed as sub-PRs that target this branch and squash-merge into it; this PR merges to
mainonce the v1.0 must-haves have landed.Landed lanes
✅ Public project toggle —
publicflag onProject(is_publiccolumn + Liquibase migration), exposed onProjectModel/ProjectDto; owner-onlyPUT /v2/projects/{projectId}/publishing(gated byPROJECT_EDIT+checkUserIsOwnerOrServerAdmin, activity-logged, cache-evicting); confirmation-guarded "Public project" switch in advanced settings.✅ Community permission (feat: community permissions for public projects #3770) — authenticated users on a public project get a computed community floor (read subset of VIEW +
translations.suggest+translation-comments.add, all languages; originCOMMUNITY) without a storedPermissionrow, so they contribute without taking a paid seat. Direct/org permissions and admin/supporter elevation layer on top, so no authenticated user is below a non-member; anonymous users get nothing. Member emails + member count are redacted behindMEMBERS_VIEW(REST + websocket); out-of-surface endpoints are gated (MT credits →ORGANIZATION_QUOTAS_VIEW, import-settings →TRANSLATIONS_EDIT(mirrors the import menu gatetranslations.edit+keys.view), branch-merge →BRANCH_MANAGEMENT, blocking-tasks → task-view-or-assigned).✅ List-row public indicator (feat: public badge + organization on project list rows #3771) — public projects show a second line under the project name in the shared list row (
DashboardProjectListItem): an outlinedpublicbadge + organization name. AddspublictoProjectWithStatsModel+ assembler. Sole indicator (no project-detail icon).✅ Suggestion resolution split (feat: split suggestion accept into "accept only" and "accept and decline others" #3776) — splits the single suggestion Accept into "Accept only" (
declineOther=false, leaves the competing suggestions active) and "Accept and decline others" (declineOther=true, prior behavior). Inline row actions are ✓ Accept-only and ✕ Decline; an⋮overflow menu holds Accept-and-decline-others and Delete (own suggestions only). Frontend-only — the backend already supporteddeclineOther. Optimistic cache keeps the surviving sibling visible until refetch (vitest-covered). Two new i18n keys created in "Tolgee itself".✅ Suggestion moderation (feat: add translation-suggestions.manage permission scope #3785) — new
translation-suggestions.managescope lets project members delete suggestions authored by other users (previously author-only). Own per-language dimension (suggestManageLanguages, new join table + Liquibase migration);SuggestandManageare grouped under a new "Suggestions" permission category, each with its own language selector. Granted to the EDIT/MANAGE presets; the suggestion list endpoint acceptssuggestORmanageso moderators see what they can act on. Deletion is language-restricted like the sibling suggestion actions; decline/accept stay ontranslations.state-edit. New i18n keys in "Tolgee itself".✅ Suggestion display (feat: show up to 3 translation suggestions per cell by default #3774) — translations read view embeds up to 3 active suggestions per cell (was 1), newest-first via a windowed top-N query (cap
MAX_DISPLAYED_SUGGESTIONS=3,created_at desc, id desc); the existing+Noverflow badge is the "more" affordance (no separate button). Stays capped at 3 across the editor open/close, mutate, and suggest-create paths;+Nrestyled as an inline circle on the last suggestion row.✅ Public projects view (feat: public projects view (Community Translation v1.0) #3775) — logged-out-capable
/public-projectspage listing all public projects (stats, paged + search) via anonymousGET /v2/public/projects/with-stats(@Transactional(readOnly=true), filters guard the anonymous read so it is side-effect-free; the community-permission floor from feat: community permissions for public projects #3770 applies for logged-in visitors). Reuses the projects-list UI (sharedProjectsListextracted fromProjectListView); community-translation banner (Figma-matched gradient + dev-mouse mascot + Suggest/Comment bullets, no Vote), left-anchored search shown only above a >5 project threshold,LOG IN/SIGN UPtop bar, no org switcher.DashboardProjectListItemgainsvariant='public': member affordances (⋮ menu / QA / translations) suppressed, whole-row click opens the project when logged-in (community VIEW) else routes to login.✅ Projects-page redesign (feat: community projects page and switcher navigation entry #3777) — projects list header redesigned: centered "Projects" title with the org switcher relocated beside it (
standaloneTitlehides the separator, adds top spacing, stacks search on its own row); every non-list page keeps the top-left switcher. Synthetic "Community translation" switcher entry navigates to/community-projects(does not switch org) — implemented but temporarily disabled pending contributor tracking (its e2e tests are skipped with a re-enable TODO)./community-projectspage reuses the projects-list shell, ignores the selected org, lists all public projects, email-verification gated, with the community-translation banner on top (diverges from the pitch's "no banner" — designer request).DashboardProjectListItemgains a public grid variant that drops the controls column entirely — no reserved space (default title width 150→180px, smaller breakpoints unchanged). New i18n keys in "Tolgee itself".✅ Community access to public-project orgs (feat: community access to public-project organizations #3792) — opening a public project auto-switches the preferred org; for non-members this previously 403'd because org access only recognized stored membership/permission rows. Extends the org view floor (
canUserViewStrictOrPublic= direct permission / stored org role OR the org owns a publicly visible project) so community and direct-permission users can view the org and set it as preferred — without a dedicated role (an earlier GUEST-role iteration was removed; below-member users hold no role). Anything beyond viewing still requiresMEMBER+. Reduced preferred-org model below MEMBER (activeCloudSubscriptionhidden; newPrivateOrganizationModel.limitedViewdrives the community project-list view). Guest-visible surface scoped to accessible projects — org GETs (rolenull), project listings, languages/base-languages, glossary reads incl. CSV export (one canonicalProjectRepository.BELOW_MEMBER_ACCESSIBLE_PROJECTpredicate), llm-providers (name/type/token-credit pricing only),/leave. Preference healing writes on stale/missing preference; below-member viewers excluded from member listings, seat stats, and assignee search. Billing repo should audit its org-scoped@UseDefaultPermissionsendpoints for the widened floor.Pending lanes (this branch)
GET /v2/projects/{id}/machine-translation-credit-balancenow requiresORGANIZATION_QUOTAS_VIEW; granular permissions / API keys without it get 403 and must be re-granted.BRANCH_MANAGEMENT.Notes
decline/acceptare unchanged).Deliberate inline style literals (no matching MUI theme token)
These Figma-exact values are kept inline on purpose — single-use surfaces with no matching
themetoken; not folded intotheme.typography/theme.spacing:heading 40px/700/lh1.167/-1.5px (rendered as
h1for semantics, visual is the Figma override);subtext max-width 561px; mascot-zone reserve padding-right 260px; mouse height 190px / bottom -15px;
bullet icons 21×22px; gradient stop 69%.
TrialChip.tsx) / 6px vertical padding.StyledPublicChiplabel: 13px.Summary by CodeRabbit
Summary
New Features
translation-suggestions.manage(per-language suggestion management) andorganization-quotas.view.Bug Fixes
Tests